add uber.config model for Uber Direct integration and delivery settings

This commit is contained in:
Alaguraj0361 2026-09-18 12:25:49 +05:30
parent a209e448a0
commit 940a3f7a58

View File

@ -110,10 +110,8 @@ class UberConfig(models.Model):
return "https://api.uber.com/v1" return "https://api.uber.com/v1"
def _get_token_url(self): def _get_token_url(self):
"""Return OAuth token URL based on environment""" """Return OAuth token URL (login.uber.com supports both Sandbox and Production)"""
self.ensure_one() self.ensure_one()
if self.environment == 'sandbox':
return "https://sandbox-login.uber.com/oauth/v2/token"
return "https://login.uber.com/oauth/v2/token" return "https://login.uber.com/oauth/v2/token"
def _get_access_token(self): def _get_access_token(self):
@ -170,31 +168,63 @@ class UberConfig(models.Model):
self.ensure_one() self.ensure_one()
current_scope = (self.scope or '').strip() current_scope = (self.scope or '').strip()
if not current_scope or current_scope != 'eats.deliveries': if not current_scope or current_scope != 'eats.deliveries':
# Default to required delivery scope
self.write({'scope': 'eats.deliveries'}) self.write({'scope': 'eats.deliveries'})
try: try:
token = self._get_access_token() token = self._get_access_token()
message = "Connection Successful! Token retrieved successfully using scope 'eats.deliveries'. Uber Direct delivery quotes and couriers are ready." message = "Connection Successful! Token retrieved successfully using scope 'eats.deliveries'. Uber Direct live delivery quotes and couriers are fully active."
msg_type = "success" return self._return_notification(message, "success")
return self._return_notification(message, msg_type)
except UserError as e: except UserError as e:
err_str = str(e) err_str = str(e)
client_id = (self.client_id or '').strip()
client_secret = (self.client_secret or '').strip()
# Diagnostic 1: Check if credentials work on Production login vs Sandbox login
org_token = None
detected_env = None
for env_name, token_url in [
('production', 'https://login.uber.com/oauth/v2/token'),
('sandbox', 'https://sandbox-login.uber.com/oauth/v2/token')
]:
try:
r = requests.post(token_url, data={
'client_id': client_id,
'client_secret': client_secret,
'grant_type': 'client_credentials',
'scope': 'direct.organizations'
}, timeout=10)
if r.status_code == 200:
detected_env = env_name
org_token = r.json().get('access_token')
break
except Exception:
pass
if detected_env:
env_mismatch_note = ""
if self.environment != detected_env:
env_mismatch_note = f"\n\nNote: Your credentials matched the {detected_env.upper()} environment, but Odoo is currently set to '{self.environment.capitalize()}'. Change Environment to '{detected_env.capitalize()}'."
message = (
f"Credentials Authenticated Successfully!\n\n"
f"Your Client ID and Secret are valid and connected to your Uber Direct organization (scope: 'direct.organizations').{env_mismatch_note}\n\n"
f"To enable 'eats.deliveries' (Courier Dispatch & Live Quotes):\n"
f"1. For Sandbox Testing: In direct.uber.com, click 'Switch to testing' (top right of Developer page), then copy the testing Client ID & Secret into Odoo and set Environment to 'Sandbox / Testing'.\n"
f"2. For Live Production: In direct.uber.com, click 'Set up' under Billing (left menu) to add a payment card/method and add your store address under Locations. Uber activates 'eats.deliveries' once billing is attached."
)
return self._return_notification(message, "warning")
if "invalid_scope" in err_str.lower() or "scope" in err_str.lower(): if "invalid_scope" in err_str.lower() or "scope" in err_str.lower():
message = ( message = (
"Uber Direct Permission Required: Your Uber Client ID requires the 'eats.deliveries' scope.\n\n" "Uber Direct Permission Required: Your Uber Client ID requires the 'eats.deliveries' scope.\n\n"
"How to resolve:\n" "How to resolve:\n"
"1. Go to https://developer.uber.com and log in.\n" "1. For Sandbox: In direct.uber.com, click 'Switch to testing' to use testing credentials.\n"
"2. Check that your app was created with the 'Uber Direct' / 'Deliveries' API Suite (not 'Others').\n" "2. For Production: Set up Billing and Location in direct.uber.com to activate live courier dispatch.\n"
"3. If created as 'Others', click 'Create Application' and choose 'Uber Direct' / 'Deliveries'.\n" "3. Ensure Environment in Odoo matches (Sandbox vs Production)."
"4. Under 'Access Token' / 'Products', ensure 'eats.deliveries' is active."
) )
msg_type = "warning" return self._return_notification(message, "warning")
else:
message = f"Connection Failed: {err_str}"
msg_type = "danger"
return self._return_notification(message, msg_type) return self._return_notification(f"Connection Failed: {err_str}", "danger")
def _auth_with_scope(self, scope_to_test): def _auth_with_scope(self, scope_to_test):
"""Helper to test a specific scope without saving""" """Helper to test a specific scope without saving"""
@ -460,11 +490,33 @@ class UberConfig(models.Model):
'raw_error': data 'raw_error': data
} }
# 2. Out of range / undeliverable error from Uber (Live coverage check) # 2. Tax form / Billing profile required
if any(x in code.lower() or x in msg.lower() for x in ['out_of_range', 'out of range', 'outside', 'undeliverable', 'address_undeliverable', 'coverage', 'unserviceable']): if 'tax_form' in msg.lower() or 'customer_blocked' in code.lower():
tax_err = _(
"Uber Direct Account Setup Notice: Please complete your tax/billing details at "
"https://direct.uber.com/accounts/%s/billing to enable live deliveries."
) % (customer_id or '')
if pricing_source == 'uber_fallback' and dropoff_data:
dist_result = self.calculate_distance_quote(dropoff_data, company)
dist_result['warning'] = tax_err
return dist_result
return { return {
'success': False, 'success': False,
'error': _("Uber Direct: This address is outside Uber's delivery coverage area. Please choose Store Pickup."), 'error': tax_err,
'code': code,
'raw_error': data
}
# 3. Out of range / undeliverable error from Uber (Live coverage check)
if any(x in code.lower() or x in msg.lower() for x in ['out_of_range', 'out of range', 'outside', 'undeliverable', 'address_undeliverable', 'coverage', 'unserviceable']):
details = data.get('metadata', {}).get('details') if isinstance(data.get('metadata'), dict) else ''
if details:
coverage_err = _("Uber Direct: %s Please select an address closer to the restaurant or choose Store Pickup.") % details
else:
coverage_err = _("Uber Direct: This address is outside Uber's delivery coverage area. Please choose Store Pickup.")
return {
'success': False,
'error': coverage_err,
'code': code, 'code': code,
'raw_error': data 'raw_error': data
} }