8000 Syncing from upstream odoo/odoo (staging.saas-18.3) by bt-admin · Pull Request #33743 · brain-tec/odoo · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Syncing from upstream odoo/odoo (staging.saas-18.3) #33743

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Jun 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
b47b692
[FIX] base: malaysian address display state name
ande-odoo May 30, 2025
2d864b0
[IMP] l10n_in_ewaybill_stock: remove transporter gst validation
meba-odoo May 21, 2025
d276f4b
[FIX] l10n_sa_edi: exclude retention tax when computing taxes
LouisGobert May 7, 2025
964f840
[FIX] account_edi_ubl_cii: Xrechnung BuyerReference field placeholder
nape-odoo Jun 5, 2025
c72db36
[FIX] web: fix concurrency test failing randomly
aab-odoo Jun 6, 2025
54b9e03
[FIX] point_of_sale: save customer when setting it in restaurant
artn-odoo May 27, 2025
b989bf2
[FIX] account_peppol: fix a function signature
svfu-odoo Jun 10, 2025
31d0510
[FIX] l10n_es_edi_tbai: Set correct regime code '19' for REAGYP taxes
dvsh-odoo May 22, 2025
9b7e2fa
[FIX] im_livechat: hide button rule ignored
tsm-odoo Jun 10, 2025
ba31ef6
[FIX] l10n_jo_edi: improve HTTP 403 error message
LouisGobert May 30, 2025
06718b5
[FIX] discuss: add comments for rtc service
ThanhDodeurOdoo Jun 10, 2025
407afbd
[FIX] google_calendar: avoid sending notification for old events
AbdelrahmanFawzy1 Apr 28, 2025
cee2074
[FIX] l10n_it_edi_withholding: prevent existing tax loaded at install
gteboul May 27, 2025
9bfc71a
[FIX] web_editor: fix video alignment in website partner description
walidsahli May 30, 2025
772df13
[FIX] l10n_ro_edi_stock: remove country restriction for carrier partner
dhongu May 31, 2025
660bd8c
[FIX] l10n_ro_edi_stock: remove unnecessary blank line
dhongu May 31, 2025
0cb3c13
[FW][FIX] l10n_ro_edi_stock: remove country restriction for carrier p…
robodoo Jun 11, 2025
2dbe4bc
[FIX] crm: prevent error when clicking AI icon without a record
8000 assh-odoo Jun 5, 2025
e91e18e
[IMP] portal: export SignatureForm component
kig-odoo Jun 10, 2025
385d205
[FIX] base: prevent error when adding submenu without specifying menu…
assh-odoo May 16, 2025
27d6402
[FIX] spreadsheet: correct sorted measure id
LucasLefevre May 23, 2025
c114c83
[FIX] mrp: apply putaway strategy when unbuilding an order
DjamelTouati Jun 2, 2025
be31675
[FIX] l10n_es_edi_sii: don't die on 0€ not_subject_loc invoices
yajo Dec 4, 2024
c5bf70e
[FIX] account: pick correct accounts for foreign tax groups
dylankiss May 26, 2025
bd6873f
[FIX] account,l10n_*: fix tax (closing) accounts
dylankiss May 15, 2025
ed98999
[FIX] pos_sale_loyalty: ignore sale loyalty
robinengels May 14, 2025
bbba54a
[FIX] l10n_lu: tax report: make sure to empty subformula on aggregation
oco-odoo Jun 11, 2025
88a9223
[FIX] l10n_tz_account: fix tax grids of refund taxes & missing fp
kitan191 Jun 5, 2025
136650c
[IMP] iot_box_image: led manager as a service
loouis-t May 28, 2025
f9d7604
[FIX] payment{,_stripe}: avoid logging secret values
lvsz May 27, 2025
f48520c
[FIX] web(site): error dialog displayed when unloading page
res-odoo May 30, 2025
9cd7188
[FIX] mail: no flicker on opening discuss conversation
alexkuhn Jun 11, 2025
e0ad1d6
[FIX] mail: ensure portals can read their notifications
Abridbus Mar 20, 2025
df6236a
[FIX] mail: crash when hovering unknown reaction
tsm-odoo Jun 11, 2025
71e3784
[PERF] crm: Add index on default order
pivi-odoo Jun 11, 2025
9e4b6ab
[IMP] point_of_sale: add `keepCommands` options for serialization
manv-afk Jun 4, 2025
dea711c
[FIX] fleet: display driver name in kanban
pimodoo Jun 11, 2025
5e0debd
[FIX] account,l10n_{bo,es}: tax closing fix followup
dylankiss Jun 3, 2025
5fc2bb1
[FIX] spreadsheet: wrong show value for waterfall/pyramid chart
hokolomopo Jun 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions addons/account/data/template/account.account-generic_coa.csv
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"owner_current_account","Owner's Current Account","1220","asset_receivable","","True","True"
"prepaid_expenses","Prepaid Expenses","1280","asset_current","","False","False"
"tax_paid","Tax Paid","1310","asset_current","","False","False"
"tax_receivable","Tax Receivable","1320","asset_current","","False","False"
"tax_receivable","Tax Receivable","1320","asset_receivable","","True","True"
"prepayments","Prepayments","1410","asset_prepayments","","False","False"
"fixed_assets","Fixed Asset","1510","asset_fixed","","False","False"
"non_current_assets","Non-current assets","1910","asset_non_current","","False","False"
Expand All @@ -22,7 +22,7 @@
"employee_payroll_taxes","Employee Payroll Taxes","2301","liability_current","","True","False"
"employer_payroll_taxes","Employer Payroll Taxes","2302","liability_current","","True","False"
"tax_received","Tax Received","2510","liability_current","","False","False"
"tax_payable","Tax Payable","2520","liability_current","","False","False"
"tax_payable","Tax Payable","2520","liability_payable","","True","True"
"non_current_liabilities","Non-current Liabilities","2910","liability_non_current","","False","False"
"capital","Capital","3010","equity","","False","False"
"dividends","Dividends","3020","equity","","False","False"
Expand Down
26 changes: 26 additions & 0 deletions addons/account/models/account_tax.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,32 @@ def _compute_country_id(self):
for group in self:
group.country_id = group.company_id.account_fiscal_country_id or group.company_id.country_id

@api.constrains('tax_payable_account_id', 'tax_receivable_account_id')
def _check_accounts_configuration(self):
account_fields = self.env['account.account']._fields
account_type_selection_values = dict(account_fields['account_type']._description_selection(self.env))
reconcile_field_name = account_fields['reconcile'].get_description(self.env)['string']
non_trade_field_name = account_fields['non_trade'].get_description(self.env)['string']

for group in self:
for field_name in ('tax_payable_account_id', 'tax_receivable_account_id'):
if group[field_name] and not (
group[field_name].account_type in ('asset_receivable', 'liability_payable')
and group[field_name].reconcile
and group[field_name].non_trade
):
raise ValidationError(
self.env._(
'%(tax_account)s (%(account_name)s) should be an account of type "%(receivable)s" or "%(payable)s" with both options "%(allow_reconciliation)s" and "%(non_trade)s" enabled.',
tax_account=self._fields[field_name].get_description(self.env)['string'],
account_name=group[field_name].display_name,
receivable=account_type_selection_values['asset_receivable'],
payable=account_type_selection_values['liability_payable'],
allow_reconciliation=reconcile_field_name,
non_trade=non_trade_field_name,
),
)


class AccountTax(models.Model):
_name = 'account.tax'
Expand Down
5 changes: 3 additions & 2 deletions addons/account/models/chart_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -920,8 +920,9 @@ def create_foreign_tax_account(existing_account, additional_label, reconcilable=
'name': f"{existing_account.name} - {additional_label}",
'code': new_code,
'account_type': existing_account.account_type,
'reconcile': reconcilable or existing_account.reconcile,
'non_trade': existing_account.non_trade,
'company_ids': [Command.link(company.id)],
'reconcile': reconcilable,
})

existing_accounts = {'': None, None: None} # keeps tracks of the created account by foreign xml_id
Expand Down Expand Up @@ -1018,7 +1019,7 @@ def create_foreign_tax_account(existing_account, additional_label, reconcilable=
# Assign the account based on the map
for field, _account_name in field_and_names:
for tax_group in tax_group_data.values():
tax_group[field] = existing_accounts.get(account_template_xml_id)
tax_group[field] = existing_accounts.get(tax_group.get(field))

for tax_template in tax_data.values():
# This is required because the country isn't provided directly by the template
Expand Down
2 changes: 2 additions & 0 deletions addons/account/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ def collect_company_accounting_data(cls, company):
*account_company_domain,
('account_type', '=', 'liability_payable')
], limit=1),
'default_tax_account_receivable': company.account_purchase_tax_id.tax_group_id.tax_receivable_account_id,
'default_tax_account_payable': company.account_sale_tax_id.tax_group_id.tax_payable_account_id,
'default_account_assets': AccountAccount.search([
*account_company_domain,
('account_type', '=', 'asset_fixed')
Expand Down
16 changes: 11 additions & 5 deletions addons/account/tests/test_multivat.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,28 @@ def test_data_getter(self, template_code):
f'{external_id_prefix}test_account_tax_recoverable_template': {
'name': f'{external_id_prefix}tax recoverable',
'code': '411000',
'account_type': 'asset_current',
'account_type': 'asset_receivable',
'reconcile': True,
'non_trade': True,
},
f'{external_id_prefix}test_account_tax_receivable_template': {
'name': f'{external_id_prefix}tax recoverable',
'name': f'{external_id_prefix}tax receivable',
'code': '411200',
'account_type': 'asset_current',
'account_type': 'asset_receivable',
'reconcile': True,
'non_trade': True,
},
f'{external_id_prefix}test_account_advance_payment_tax_template': {
'name': f'{external_id_prefix}advance tax payment',
'code': '411900',
'account_type': 'asset_current',
},
f'{external_id_prefix}test_account_tax_payable_template': {
'name': f'{external_id_prefix}tax recoverable',
'name': f'{external_id_prefix}tax payable',
'code': '451200',
'account_type': 'liability_current',
'account_type': 'liability_payable',
'reconcile': True,
'non_trade': True,
},
f'{external_id_prefix}test_account_cash_basis_transition_account_id': {
'name': f'{external_id_prefix}cash basis transition account',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ def _export_invoice_vals(self, invoice):
# EXTENDS account.edi.xml.ubl_bis3
vals = super()._export_invoice_vals(invoice)
vals['vals']['customization_id'] = self._get_customization_ids()['xrechnung']
if not vals['vals'].get('buyer_reference'):
vals['vals']['buyer_reference'] = 'N/A'
return vals

def _export_invoice_constraints(self, invoice, vals):
Expand Down
8 changes: 6 additions & 2 deletions addons/account_peppol/models/account_move.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,12 @@ def _compute_peppol_move_state(self):
else:
move.peppol_move_state = move.peppol_move_state

def _notify_by_email_prepare_rendering_context(self, message, **kwargs):
render_context = super()._notify_by_email_prepare_rendering_context(message, **kwargs)
def _notify_by_email_prepare_rendering_context(self, message, msg_vals=False, model_description=False,
force_email_company=False, force_email_lang=False):
render_context = super()._notify_by_email_prepare_rendering_context(
message, msg_vals=msg_vals, model_description=model_description,
force_email_company=force_email_company, force_email_lang=force_email_lang
)
invoice = render_context['record']
invoice_country = invoice.commercial_partner_id.country_code
company_country = invoice.company_id.country_code
Expand Down
16 changes: 16 additions & 0 deletions addons/calendar/models/calendar_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,22 @@ def _get_default_privacy_domain(self):
'&', ('privacy', '=', False), ('user_id', 'in', public_calendars_settings)
]

def _is_event_over(self):
"""Check if the event is over. This method is used to check if the event
should trigger invitations with Google Calendar.
:return: True if the event is over, False otherwise
"""
self.ensure_one()
now = fields.Datetime.now()
today = fields.Date.today()

# For all-day events
if self.allday:
return self.stop_date and self.stop_date < today

# For timed events
return self.stop and self.stop < now

# ------------------------------------------------------------
# ACTIONS
# ------------------------------------------------------------
Expand Down
16 changes: 16 additions & 0 deletions addons/calendar/models/calendar_recurrence.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,3 +603,19 @@ def _get_rrule(self, dtstart=None):
return rrule.rrule(
freq_to_rrule(freq), **rrule_params
)

def _is_event_over(self):
"""Check if all events in this recurrence are in the past.
:return: True if all events are over, False otherwise
"""
self.ensure_one()
if not self.calendar_event_ids:
return False

now = fields.Datetime.now()
today = fields.Date.today()

return all(
(event.stop_date < today if event.allday else event.stop < now)
for event in self.calendar_event_ids
)
1 change: 1 addition & 0 deletions addons/crm/models/crm_lead.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ class CrmLead(models.Model):
)
_user_id_team_id_type_index = models.Index("(user_id, team_id, type)")
_create_date_team_id_idx = models.Index("(create_date, team_id)")
_default_order_idx = models.Index('(priority DESC, id DESC) WHERE active IS TRUE')

@api.constrains('probability', 'stage_id')
def _check_won_validity(self):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class CrmPlsTooltipButton extends Component {
} else {
// Apply pending changes. They may change probability
await this.props.record.save();
if (status(this) === "destroyed") {
if (status(this) === "destroyed" || !this.props.record.resId) {
return;
}

Expand Down
5 changes: 4 additions & 1 deletion addons/fleet/views/fleet_vehicle_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,10 @@
<field class="fw-bolder fs-5" name="model_id"/>
</div>
<field name="tag_ids" widget="many2many_tags" options="{'color_field': 'color'}"/>
<field t-if="record.driver_id.raw_value" name="driver_id" widget="many2one_avatar" options="{'display_avatar_name': True}" class="small pt-1 pb-1"/>
<div class="d-flex gap-1" t-if="record.driver_id.raw_value">
<field name="driver_id" widget="many2one_avatar"/>
<field name="driver_id" class="small pt-1 pb-1"/>
</div>
<div class="small">
<t t-if="record.future_driver_id.raw_value">Future Driver : <field name="future_driver_id"/></t>
</div>
Expand Down
4 changes: 3 additions & 1 deletion addons/google_calendar/models/google_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ def _google_patch(self, google_service: GoogleCalendarService, google_id, values
with google_calendar_token(self.env.user.sudo()) as token:
if token:
try:
send_updates = not self._is_event_over()
google_service.google_service = google_service.google_service.with_context(send_updates=send_updates)
google_service.patch(google_id, values, token=token, timeout=timeout)
except HTTPError as e:
if e.response.status_code in (400, 403):
Expand Down Expand Up @@ -308,7 +310,7 @@ def _google_insert(self, google_service: GoogleCalendarService, values, timeout=
with google_calendar_token(self.env.user.sudo()) as token:
if token:
try:
send_updates = self._context.get('send_updates', True)
send_updates = self._context.get('send_updates', True) and not self._is_event_over()
google_service.google_service = google_service.google_service.with_context(send_updates=send_updates)
google_values = google_service.insert(values, token=token, timeout=timeout, need_video_call=self._need_video_call())
self.with_context(dont_notify=True).write(self._get_post_sync_values(values, google_values))
Expand Down
110 changes: 83 additions & 27 deletions addons/google_calendar/tests/test_sync_odoo2google.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,33 +599,6 @@ def test_all_event_with_tz_updated(self):
'transparency': 'opaque',
}, timeout=3)

def test_send_update_do_request(self):
self.env.cr.postcommit.clear()
with self.mock_google_service():
event = self.env['calendar.event'].create({
'name': "Event",
'allday': True,
'start': datetime(2020, 1, 15),
'stop': datetime(2020, 1, 15),
'need_sync': False,
})
event.with_context(send_updates=True)._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertGoogleEventSendUpdates('all')

def test_not_send_update_do_request(self):
with self.mock_google_service():
event = self.env['calendar.event'].create({
'name': "Event",
'allday': True,
'start': datetime(2020, 1, 15),
'stop': datetime(2020, 1, 15),
'need_sync': False,
})
event.with_context(send_updates=False)._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertGoogleEventSendUpdates('none')

@patch_api
def test_recurrence_delete_single_events(self):
"""
Expand Down Expand Up @@ -1011,3 +984,86 @@ def test_skip_sync_for_non_synchronized_users_new_events(self, mock_sync_request
],
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: record.id}},
})

def test_event_over_send_updates(self):
"""Test that events that are over don't sent updates to attendees."""
with self.mock_datetime_and_now("2023-01-10"):
self.env.cr.postcommit.clear()
with self.mock_google_service():
past_event = self.env['calendar.event'].create({
'name': "Event",
'start': datetime(2020, 1, 15, 8, 0),
'stop': datetime(2020, 1, 15, 9, 0),
'need_sync': False,
})
past_event._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertTrue(past_event._is_event_over(), "Event should be considered over")
self.assertGoogleEventSendUpdates('none')

def test_event_not_over_send_updates(self):
"""Test that events that are not over send updates to attendees."""
with self.mock_datetime_and_now("2023-01-10"):
self.env.cr.postcommit.clear()
with self.mock_google_service():
future_date = datetime(2023, 1, 20, 8, 0) # Fixed date instead of datetime.now()
future_event = self.env['calendar.event'].create({
'name': "Future Event",
'start': future_date,
'stop': future_date + relativedelta(hours=1),
'need_sync': False,
})
# Sync the event and verify send_updates is set to 'all'
future_event._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertFalse(future_event._is_event_over(), "Future event should not be considered over")
self.assertGoogleEventSendUpdates('all')

def test_recurrence_over_send_updates(self):
"""Test that recurrences that are over don't send updates to attendees."""
with self.mock_datetime_and_now("2023-01-10"):
self.env.cr.postcommit.clear()
with self.mock_google_service():
past_event = self.env['calendar.event'].create({
'name': "Past Recurring Event",
'start': datetime(2020, 1, 15, 8, 0),
'stop': datetime(2020, 1, 15, 9, 0),
'need_sync': False,
})
past_recurrence = self.env['calendar.recurrence'].create({
'rrule': 'FREQ=WEEKLY;COUNT=2;BYDAY=WE',
'base_event_id': past_event.id,
'need_sync': False,
})
past_recurrence._apply_recurrence()
# Sync the recurrence and verify send_updates is set to 'none'
past_recurrence._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertTrue(past_recurrence._is_event_over(), "Past recurrence should be considered over")
self.assertGoogleEventSendUpdates('none')

def test_recurrence_not_over_send_updates(self):
"""Test that recurrences that are not over send updates to attendees."""
with self.mock_datetime_and_now("2023-01-10"):
self.env.cr.postcommit.clear()
with self.mock_google_service():
future_date = datetime(2023, 1, 20, 8, 0)
future_event = self.env['calendar.event'].create({
'name': "Future Recurring Event",
'start': future_date,
'stop': future_date + relativedelta(hours=1),
'need_sync': False,
})
future_recurrence = self.env['calendar.recurrence'].create(
{
'rrule': 'FREQ=WEEKLY;COUNT=2;BYDAY=WE',
'base_event_id': future_event.id,
'need_sync': False,
}
)
future_recurrence._apply_recurrence()
# Sync the recurrence and verify send_updates is set to 'all'
future_recurrence._sync_odoo2google(self.google_service)
self.call_post_commit_hooks()
self.assertFalse(future_recurrence._is_event_over(), "Future recurrence should not be considered over")
self.assertGoogleEventSendUpdates('all')
3 changes: 2 additions & 1 deletion addons/google_calendar/utils/google_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ def insert(self, values, token=None, timeout=TIMEOUT, need_video_call=True):

@requires_auth_token
def patch(self, event_id, values, token=None, timeout=TIMEOUT):
url = "/calendar/v3/calendars/primary/events/%s?sendUpdates=all" % event_id
send_updates = self.google_service._context.get('send_updates', True)
url = "/calendar/v3/calendars/primary/events/%s?sendUpdates=%s" % (event_id, "all" if send_updates else "none")
headers = {'Content-type': 'application/json', 'Authorization': 'Bearer %s' % token}
self.google_service._do_request(url, json.dumps(values), headers, method='PATCH', timeout=timeout)

Expand Down
1 change: 0 additions & 1 deletion addons/hw_drivers/__init__.py