Author SHA1 Message Date
joseagrc 612821e363 Promote standalone Dominican Spanish to Tryton 8.0
Validate Tryton customizations / validate (push) Successful in 3m47s
Promote the reviewed es_DO core, module and SAO catalogs from integration/8.0 after successful CI.
2026-10-13 20:49:23 -04:00
29 changed files with 141 additions and 346 deletions
+9 -9
View File
@@ -355,11 +355,9 @@ class Move(DescriptionOriginMixin, ModelSQL, ModelView):
'''
pool = Pool()
MoveLine = pool.get('account.move.line')
Currency = pool.get('currency.currency')
line = MoveLine.__table__()
transaction = Transaction()
cursor = transaction.connection.cursor()
cast = Currency.rounding.sql_cast
for company, moves in groupby(moves, key=lambda m: m.company):
currency = company.currency
@@ -372,7 +370,7 @@ class Move(DescriptionOriginMixin, ModelSQL, ModelView):
group_by=line.move,
having=Abs(Round(
Sum(line.debit - line.credit),
currency.digits)) < cast(abs(currency.rounding)))
currency.digits)) < abs(currency.rounding))
cursor.execute(*line.update(
[line.state],
['valid'],
@@ -384,7 +382,7 @@ class Move(DescriptionOriginMixin, ModelSQL, ModelView):
group_by=line.move,
having=Abs(Round(
Sum(line.debit - line.credit),
currency.digits)) >= cast(abs(currency.rounding)))
currency.digits)) >= abs(currency.rounding))
cursor.execute(*line.update(
[line.state],
['draft'],
@@ -1446,13 +1444,16 @@ class Line(DescriptionOriginMixin, MoveLineMixin, ModelSQL, ModelView):
}])
@classmethod
def on_modification(cls, mode, lines, field_names=None):
def check_modification(cls, mode, lines, values=None, external=False):
pool = Pool()
Move = pool.get('account.move')
super().on_modification(mode, lines, field_names=field_names)
super().check_modification(
mode, lines, values=values, external=external)
if field_names is None or (field_names - cls._check_modify_exclude):
if (mode in {'create', 'delete'}
or (mode == 'write'
and values.keys() - cls._check_modify_exclude)):
journal_period_done = set()
for line in lines:
if line.move.state == 'posted':
@@ -1473,8 +1474,7 @@ class Line(DescriptionOriginMixin, MoveLineMixin, ModelSQL, ModelView):
'account.msg_delete_line_reconciled',
line=line.rec_name))
if (mode == 'write'
and field_names is not None
and field_names & cls._reconciliation_modify_disallow):
and values.keys() & cls._reconciliation_modify_disallow):
for line in lines:
if line.reconciliation:
raise AccessError(gettext(
-63
View File
@@ -767,69 +767,6 @@ class AccountTestCase(
]
move.save()
@with_transaction()
def test_move_validation(self):
"Test move validation"
pool = Pool()
Party = pool.get('party.party')
FiscalYear = pool.get('account.fiscalyear')
Journal = pool.get('account.journal')
Account = pool.get('account.account')
Move = pool.get('account.move')
Line = pool.get('account.move.line')
party = Party(name='Party')
party.save()
company = create_company()
with set_company(company):
fiscalyear = get_fiscalyear(company)
fiscalyear.save()
FiscalYear.create_period([fiscalyear])
period = fiscalyear.periods[0]
create_chart(company)
journal_revenue, = Journal.search([
('code', '=', 'REV'),
])
revenue, = Account.search([
('type.revenue', '=', True),
('closed', '=', False),
], limit=1)
receivable, = Account.search([
('type.receivable', '=', True),
('closed', '=', False),
], limit=1)
move = Move()
move.period = period
move.journal = journal_revenue
move.date = period.start_date
move.lines = [
Line(account=revenue, credit=Decimal(100)),
]
move.save()
line, = move.lines
self.assertEqual(line.state, 'draft')
move.lines += (
Line(account=receivable, debit=Decimal(100), party=party),
)
move.save()
self.assertEqual([l.state for l in move.lines], ['valid', 'valid'])
line = move.lines[-1]
line.credit = Decimal(50)
line.save()
self.assertEqual(line.state, 'draft')
line.credit = Decimal(100)
line.save()
self.assertEqual(line.state, 'valid')
@with_transaction()
def test_find_best_reconciliation(self):
"Test find best reconciliation"
@@ -32,7 +32,7 @@ this repository contains the full copyright notices and license terms. -->
<CreDtTm>${datetime.datetime.now().replace(microsecond=0).isoformat()}</CreDtTm>
<!-- Authstn -->
<NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in group.payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in group.payments).normalize(), 'f')}</CtrlSum>
<!-- PmtTpInf -->
<!-- ReqdColltnDt -->
<InitgPty>
@@ -45,7 +45,7 @@ this repository contains the full copyright notices and license terms. -->
<PmtMtd>TRF</PmtMtd>
<BtchBookg>${'true' if group.journal.sepa_batch_booking else 'false'}</BtchBookg>
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in payments).normalize(), 'f')}</CtrlSum>
<PmtTpInf>
<!-- InstrPrty -->
<SvcLvl>
@@ -77,7 +77,7 @@ this repository contains the full copyright notices and license terms. -->
</PmtId>
<!-- PmtTpInf --> <!-- EPC only at payment information level -->
<Amt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount, 'f')}</InstdAmt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount.normalize(), 'f')}</InstdAmt>
<!-- EqvtAmt -->
</Amt>
<!-- XchgRateInf -->
@@ -13,7 +13,7 @@ this repository contains the full copyright notices and license terms. -->
<CreDtTm>${datetime.datetime.now().replace(microsecond=0).isoformat()}</CreDtTm>
<!-- Authstn -->
<NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in group.payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in group.payments).normalize(), 'f')}</CtrlSum>
<!-- PmtTpInf -->
<!-- ReqdColltnDt -->
<InitgPty>
@@ -26,7 +26,7 @@ this repository contains the full copyright notices and license terms. -->
<PmtMtd>TRF</PmtMtd>
<BtchBookg>${'true' if group.journal.sepa_batch_booking else 'false'}</BtchBookg>
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in payments).normalize(), 'f')}</CtrlSum>
<PmtTpInf>
<!-- InstrPrty -->
<SvcLvl>
@@ -59,7 +59,7 @@ this repository contains the full copyright notices and license terms. -->
</PmtId>
<!-- PmtTpInf --> <!-- EPC only at payment information level -->
<Amt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount, 'f')}</InstdAmt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount.normalize(), 'f')}</InstdAmt>
<!-- EqvtAmt -->
</Amt>
<!-- XchgRateInf -->
@@ -15,7 +15,7 @@ this repository contains the full copyright notices and license terms. -->
<MsgId>${group.sepa_message_id[:35]}</MsgId>
<CreDtTm>${datetime.datetime.now().replace(microsecond=0).isoformat()}</CreDtTm>
<NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in group.payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in group.payments).normalize(), 'f')}</CtrlSum>
<InitgPty>
${PartyIdentification(group.sepa_initiating_party, id=group.journal.sepa_payable_initiator_id, with_address=False)}
</InitgPty>
@@ -25,7 +25,7 @@ this repository contains the full copyright notices and license terms. -->
<PmtMtd>TRF</PmtMtd>
<BtchBookg>${'true' if group.journal.sepa_batch_booking else 'false'}</BtchBookg>
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in payments).normalize(), 'f')}</CtrlSum>
<PmtTpInf>
<!-- InstrPrty -->
<SvcLvl>
@@ -52,7 +52,7 @@ this repository contains the full copyright notices and license terms. -->
</PmtId>
<!-- PmtTpInf --> <!-- EPC only at payment information level -->
<Amt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount, 'f')}</InstdAmt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount.normalize(), 'f')}</InstdAmt>
</Amt>
<!-- ChrgBr --> <!-- EPC only at payment information level -->
<!-- UltmtDbtr -->
@@ -32,7 +32,7 @@ this repository contains the full copyright notices and license terms. -->
<CreDtTm>${datetime.datetime.now().replace(microsecond=0).isoformat()}</CreDtTm>
<!-- Authstn -->
<NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in group.payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in group.payments).normalize(), 'f')}</CtrlSum>
<!-- PmtTpInf -->
<!-- ReqdColltnDt -->
<InitgPty>
@@ -45,7 +45,7 @@ this repository contains the full copyright notices and license terms. -->
<PmtMtd>DD</PmtMtd>
<BtchBookg>${'true' if group.journal.sepa_batch_booking else 'false'}</BtchBookg>
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in payments).normalize(), 'f')}</CtrlSum>
<PmtTpInf>
<!-- InstrPrty -->
<SvcLvl>
@@ -83,7 +83,7 @@ this repository contains the full copyright notices and license terms. -->
<EndToEndId>${payment.sepa_end_to_end_id}</EndToEndId>
</PmtId>
<!-- PmtTpInf -->
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount, 'f')}</InstdAmt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount.normalize(), 'f')}</InstdAmt>
<!-- ChrgBr --> <!-- EPC only at payment information level -->
<DrctDbtTx>
<MndtRltdInf py:with="mandate = payment.sepa_mandate">
@@ -13,7 +13,7 @@ this repository contains the full copyright notices and license terms. -->
<CreDtTm>${datetime.datetime.now().replace(microsecond=0).isoformat()}</CreDtTm>
<!-- Authstn -->
<NbOfTxs>${len(group.payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in group.payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in group.payments).normalize(), 'f')}</CtrlSum>
<!-- PmtTpInf -->
<!-- ReqdColltnDt -->
<InitgPty>
@@ -26,7 +26,7 @@ this repository contains the full copyright notices and license terms. -->
<PmtMtd>DD</PmtMtd>
<BtchBookg>${'true' if group.journal.sepa_batch_booking else 'false'}</BtchBookg>
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in payments).normalize(), 'f')}</CtrlSum>
<PmtTpInf>
<!-- InstrPrty -->
<SvcLvl>
@@ -64,7 +64,7 @@ this repository contains the full copyright notices and license terms. -->
<EndToEndId>${payment.sepa_end_to_end_id}</EndToEndId>
</PmtId>
<!-- PmtTpInf -->
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount, 'f')}</InstdAmt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount.normalize(), 'f')}</InstdAmt>
<!-- ChrgBr --> <!-- EPC only at payment information level -->
<DrctDbtTx>
<MndtRltdInf py:with="mandate = payment.sepa_mandate">
@@ -15,7 +15,7 @@ this repository contains the full copyright notices and license terms. -->
<MsgId>${group.sepa_message_id[:35]}</MsgId>
<CreDtTm>${datetime.datetime.now().replace(microsecond=0).isoformat()}</CreDtTm>
<NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in group.payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in group.payments).normalize(), 'f')}</CtrlSum>
<InitgPty>
${PartyIdentification(group.sepa_initiating_party, id=group.journal.sepa_receivable_initiator_id, with_address=False)}
</InitgPty>
@@ -25,7 +25,7 @@ this repository contains the full copyright notices and license terms. -->
<PmtMtd>DD</PmtMtd>
<BtchBookg>${'true' if group.journal.sepa_batch_booking else 'false'}</BtchBookg>
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in payments).normalize(), 'f')}</CtrlSum>
<PmtTpInf>
<SvcLvl>
<Cd>SEPA</Cd>
@@ -56,7 +56,7 @@ this repository contains the full copyright notices and license terms. -->
<InstrId>${payment.sepa_instruction_id}</InstrId>
<EndToEndId>${payment.sepa_end_to_end_id}</EndToEndId>
</PmtId>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount, 'f')}</InstdAmt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount.normalize(), 'f')}</InstdAmt>
<!-- ChrgBr --> <!-- EPC only at payment information level -->
<DrctDbtTx>
<MndtRltdInf py:with="mandate = payment.sepa_mandate">
@@ -26,7 +26,7 @@ this repository contains the full copyright notices and license terms. -->
<MsgId>${group.sepa_message_id[:35]}</MsgId>
<CreDtTm>${datetime.datetime.now().replace(microsecond=0).isoformat()}</CreDtTm>
<NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in group.payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in group.payments).normalize(), 'f')}</CtrlSum>
<InitgPty>
${PartyIdentification(group.sepa_initiating_party)}
</InitgPty>
@@ -36,7 +36,7 @@ this repository contains the full copyright notices and license terms. -->
<PmtMtd>TRF</PmtMtd>
<BtchBookg>${'true' if group.journal.sepa_batch_booking else 'false'}</BtchBookg>
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in payments).normalize(), 'f')}</CtrlSum>
<PmtTpInf>
<!-- InstrPrty -->
<SvcLvl>
@@ -62,7 +62,7 @@ this repository contains the full copyright notices and license terms. -->
<EndToEndId>${payment.sepa_end_to_end_id}</EndToEndId>
</PmtId>
<Amt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount, 'f')}</InstdAmt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount.normalize(), 'f')}</InstdAmt>
<!-- EqvtAmt -->
</Amt>
<!-- ChrgBr --> <!-- EPC only at payment information level -->
@@ -32,7 +32,7 @@ this repository contains the full copyright notices and license terms. -->
<MsgId>${group.sepa_message_id[:35]}</MsgId>
<CreDtTm>${datetime.datetime.now().replace(microsecond=0).isoformat()}</CreDtTm>
<NbOfTxs>${sum(len(payments) for _, payments in group.sepa_payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in group.payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in group.payments).normalize(), 'f')}</CtrlSum>
<InitgPty>
${PartyIdentification(group.sepa_initiating_party)}
</InitgPty>
@@ -42,7 +42,7 @@ this repository contains the full copyright notices and license terms. -->
<PmtMtd>DD</PmtMtd>
<BtchBookg>${'true' if group.journal.sepa_batch_booking else 'false'}</BtchBookg>
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${format(sum(p.amount for p in payments), 'f')}</CtrlSum>
<CtrlSum>${format(sum(p.amount for p in payments).normalize(), 'f')}</CtrlSum>
<PmtTpInf>
<SvcLvl>
<Cd>SEPA</Cd>
@@ -73,7 +73,7 @@ this repository contains the full copyright notices and license terms. -->
<InstrId>${payment.sepa_instruction_id}</InstrId>
<EndToEndId>${payment.sepa_end_to_end_id}</EndToEndId>
</PmtId>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount, 'f')}</InstdAmt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${format(payment.amount.normalize(), 'f')}</InstdAmt>
<DrctDbtTx>
<MndtRltdInf py:with="mandate = payment.sepa_mandate">
<MndtId>${mandate.identification}</MndtId>
+13 -13
View File
@@ -90,7 +90,7 @@ this repository contains the full copyright notices and license terms. -->
<py:otherwise>
<cac:PaymentTerms py:for="line in this.invoice.lines_to_pay">
<cbc:Note py:if="this.invoice.payment_term and this.invoice.payment_term.description">${this.invoice.payment_term.description}</cbc:Note>
<cbc:Amount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.amount, 'f')}</cbc:Amount>
<cbc:Amount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.amount.normalize(), 'f')}</cbc:Amount>
<cbc:PaymentDueDate>${line.maturity_date}</cbc:PaymentDueDate>
</cac:PaymentTerms>
</py:otherwise>
@@ -101,16 +101,16 @@ this repository contains the full copyright notices and license terms. -->
<cbc:AllowanceChargeReasonCode py:if="reason_code">${reason_code}</cbc:AllowanceChargeReasonCode>
</py:with>
<cbc:AllowanceChargeReason>${allowance_charge.product.name}</cbc:AllowanceChargeReason>
<cbc:Amount py:attrs="{'currencyID': this.invoice.currency.code}">${format(abs(allowance_charge.amount), 'f')}</cbc:Amount>
<cbc:Amount py:attrs="{'currencyID': this.invoice.currency.code}">${format(abs(allowance_charge.amount).normalize(), 'f')}</cbc:Amount>
<cac:TaxCategory py:for="tax_line in allowance_charge.invoice_taxes">
${TaxCategory(tax_line.tax)}
</cac:TaxCategory>
</cac:AllowanceCharge>
<cac:TaxTotal py:for="group, lines, amount in this.taxes">
<cbc:TaxAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(-amount, 'f')}</cbc:TaxAmount>
<cbc:TaxAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((-amount).normalize(), 'f')}</cbc:TaxAmount>
<cac:TaxSubtotal py:for="line in lines">
<cbc:TaxableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(-line.base, 'f')}</cbc:TaxableAmount>
<cbc:TaxAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(-line.amount, 'f')}</cbc:TaxAmount>
<cbc:TaxableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((-line.base).normalize(), 'f')}</cbc:TaxableAmount>
<cbc:TaxAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((-line.amount).normalize(), 'f')}</cbc:TaxAmount>
<cbc:Percent py:if="line.tax.type == 'percentage' and not (specification or '').startswith('peppol')">${format((line.tax.rate * 100).normalize(), 'f')}</cbc:Percent>
<cac:TaxCategory>
${TaxCategory(line.tax)}
@@ -118,19 +118,19 @@ this repository contains the full copyright notices and license terms. -->
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(-this.invoice.untaxed_amount, 'f')}</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(-this.invoice.untaxed_amount, 'f')}</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(-(this.invoice.untaxed_amount + this.invoice.tax_amount), 'f')}</cbc:TaxInclusiveAmount>
<cbc:LineExtensionAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((-this.invoice.untaxed_amount).normalize(), 'f')}</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((-this.invoice.untaxed_amount).normalize(), 'f')}</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((-(this.invoice.untaxed_amount + this.invoice.tax_amount)).normalize(), 'f')}</cbc:TaxInclusiveAmount>
<py:if test="this.invoice.total_amount != (this.invoice.untaxed_amount + this.invoice.tax_amount)">
<cbc:PayableRoundingAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(-(this.invoice.total_amount - this.invoice.untaxed_amount - this.invoice.tax_amount), 'f')}</cbc:PayableRoundingAmount>
<cbc:PayableRoundingAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((-(this.invoice.total_amount - this.invoice.untaxed_amount - this.invoice.tax_amount)).normalize(), 'f')}</cbc:PayableRoundingAmount>
</py:if>
<cbc:PrepaidAmount py:if="this.prepaid_amount" py:attrs="{'currencyID': this.invoice.currency.code}">${format(-this.prepaid_amount, 'f')}</cbc:PrepaidAmount>
<cbc:PayableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(-this.invoice.total_amount + this.prepaid_amount, 'f')}</cbc:PayableAmount>
<cbc:PrepaidAmount py:if="this.prepaid_amount" py:attrs="{'currencyID': this.invoice.currency.code}">${format((-this.prepaid_amount).normalize(), 'f')}</cbc:PrepaidAmount>
<cbc:PayableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((-this.invoice.total_amount + this.prepaid_amount).normalize(), 'f')}</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:CreditNoteLine py:for="line_id, line in enumerate(this.lines, 1)">
<cbc:ID>${line_id}</cbc:ID>
<cbc:CreditedQuantity py:attrs="{'unitCode': line.unit.unece_code if line.unit and line.unit.unece_code else 'ZZ'}">${format(-Decimal(str(line.quantity)).normalize(), 'f')}</cbc:CreditedQuantity>
<cbc:LineExtensionAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(-line.amount, 'f')}</cbc:LineExtensionAmount>
<cbc:CreditedQuantity py:attrs="{'unitCode': line.unit.unece_code if line.unit and line.unit.unece_code else 'ZZ'}">${format(-Decimal(str(line.quantity)), 'f')}</cbc:CreditedQuantity>
<cbc:LineExtensionAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((-line.amount).normalize(), 'f')}</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Description py:if="line.description">${line.description}</cbc:Description>
<cbc:Name>${line.product.name if line.product else line.summary}</cbc:Name>
+13 -13
View File
@@ -90,7 +90,7 @@ this repository contains the full copyright notices and license terms. -->
<py:otherwise>
<cac:PaymentTerms py:for="line in this.invoice.lines_to_pay">
<cbc:Note py:if="this.invoice.payment_term and this.invoice.payment_term.description">${this.invoice.payment_term.description}</cbc:Note>
<cbc:Amount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.amount, 'f')}</cbc:Amount>
<cbc:Amount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.amount.normalize(), 'f')}</cbc:Amount>
<cbc:PaymentDueDate>${line.maturity_date}</cbc:PaymentDueDate>
</cac:PaymentTerms>
</py:otherwise>
@@ -101,16 +101,16 @@ this repository contains the full copyright notices and license terms. -->
<cbc:AllowanceChargeReasonCode py:if="reason_code">${reason_code}</cbc:AllowanceChargeReasonCode>
</py:with>
<cbc:AllowanceChargeReason>${allowance_charge.product.name}</cbc:AllowanceChargeReason>
<cbc:Amount py:attrs="{'currencyID': this.invoice.currency.code}">${format(abs(allowance_charge.amount), 'f')}</cbc:Amount>
<cbc:Amount py:attrs="{'currencyID': this.invoice.currency.code}">${format(abs(allowance_charge.amount).normalize(), 'f')}</cbc:Amount>
<cac:TaxCategory py:for="tax_line in allowance_charge.invoice_taxes">
${TaxCategory(tax_line.tax)}
</cac:TaxCategory>
</cac:AllowanceCharge>
<cac:TaxTotal py:for="group, lines, amount in this.taxes">
<cbc:TaxAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(amount, 'f')}</cbc:TaxAmount>
<cbc:TaxAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(amount.normalize(), 'f')}</cbc:TaxAmount>
<cac:TaxSubtotal py:for="line in lines">
<cbc:TaxableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.base, 'f')}</cbc:TaxableAmount>
<cbc:TaxAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.amount, 'f')}</cbc:TaxAmount>
<cbc:TaxableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.base.normalize(), 'f')}</cbc:TaxableAmount>
<cbc:TaxAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.amount.normalize(), 'f')}</cbc:TaxAmount>
<cbc:Percent py:if="line.tax.type == 'percentage' and not (specification or '').startswith('peppol')">${format((line.tax.rate * 100).normalize(), 'f')}</cbc:Percent>
<cac:TaxCategory>
${TaxCategory(line.tax)}
@@ -118,19 +118,19 @@ this repository contains the full copyright notices and license terms. -->
</cac:TaxSubtotal>
</cac:TaxTotal>
<cac:LegalMonetaryTotal>
<cbc:LineExtensionAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.untaxed_amount, 'f')}</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.untaxed_amount, 'f')}</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((this.invoice.untaxed_amount + this.invoice.tax_amount), 'f')}</cbc:TaxInclusiveAmount>
<cbc:LineExtensionAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.untaxed_amount.normalize(), 'f')}</cbc:LineExtensionAmount>
<cbc:TaxExclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.untaxed_amount.normalize(), 'f')}</cbc:TaxExclusiveAmount>
<cbc:TaxInclusiveAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((this.invoice.untaxed_amount + this.invoice.tax_amount).normalize(), 'f')}</cbc:TaxInclusiveAmount>
<py:if test="this.invoice.total_amount != (this.invoice.untaxed_amount + this.invoice.tax_amount)">
<cbc:PayableRoundingAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((this.invoice.total_amount - this.invoice.untaxed_amount - this.invoice.tax_amount), 'f')}</cbc:PayableRoundingAmount>
<cbc:PayableRoundingAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((this.invoice.total_amount - this.invoice.untaxed_amount - this.invoice.tax_amount).normalize(), 'f')}</cbc:PayableRoundingAmount>
</py:if>
<cbc:PrepaidAmount py:if="this.prepaid_amount" py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.prepaid_amount, 'f')}</cbc:PrepaidAmount>
<cbc:PayableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.total_amount - this.prepaid_amount, 'f')}</cbc:PayableAmount>
<cbc:PrepaidAmount py:if="this.prepaid_amount" py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.prepaid_amount.normalize(), 'f')}</cbc:PrepaidAmount>
<cbc:PayableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((this.invoice.total_amount - this.prepaid_amount).normalize(), 'f')}</cbc:PayableAmount>
</cac:LegalMonetaryTotal>
<cac:InvoiceLine py:for="line_id, line in enumerate(this.lines, 1)">
<cbc:ID>${line_id}</cbc:ID>
<cbc:InvoicedQuantity py:attrs="{'unitCode': line.unit.unece_code if line.unit and line.unit.unece_code else 'ZZ'}">${format(Decimal(str(line.quantity)).normalize(), 'f')}</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.amount, 'f')}</cbc:LineExtensionAmount>
<cbc:InvoicedQuantity py:attrs="{'unitCode': line.unit.unece_code if line.unit and line.unit.unece_code else 'ZZ'}">${format(Decimal(str(line.quantity)), 'f')}</cbc:InvoicedQuantity>
<cbc:LineExtensionAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.amount.normalize(), 'f')}</cbc:LineExtensionAmount>
<cac:Item>
<cbc:Description py:if="line.description">${line.description}</cbc:Description>
<cbc:Name>${line.product.name if line.product else line.summary}</cbc:Name>
@@ -44,11 +44,11 @@ this repository contains the full copyright notices and license terms. -->
</py:def>
<py:def function="TradeTax(tax, amount=None, base=None)">
<ram:ApplicableTradeTax>
<ram:CalculatedAmount py:if="amount" py:attrs="{'currencyID': this.invoice.currency.code}">${format(amount * this.type_sign, 'f')}</ram:CalculatedAmount>
<ram:CalculatedAmount py:if="amount" py:attrs="{'currencyID': this.invoice.currency.code}">${format((amount * this.type_sign).normalize(), 'f')}</ram:CalculatedAmount>
<ram:TypeCode py:if="tax.unece_code">${tax.unece_code}</ram:TypeCode>
<ram:ExemptionReasonCode py:if="hasattr(tax, 'vatex_code') and tax.vatex_code">${tax.vatex_code}</ram:ExemptionReasonCode>
<ram:ExemptionReason py:if="tax.legal_notice">${tax.legal_notice}</ram:ExemptionReason>
<ram:BasisAmount py:if="base">${format(base * this.type_sign, 'f')}</ram:BasisAmount>
<ram:BasisAmount py:if="base">${format((base * this.type_sign).normalize(), 'f')}</ram:BasisAmount>
<ram:CategoryCode py:if="tax.unece_category_code">${tax.unece_category_code}</ram:CategoryCode>
<ram:RateApplicablePercent py:if="tax.type == 'percentage'">${format((tax.rate * 100).normalize(), 'f')}</ram:RateApplicablePercent>
</ram:ApplicableTradeTax>
@@ -74,18 +74,18 @@ this repository contains the full copyright notices and license terms. -->
</ram:SpecifiedTradeProduct>
<ram:SpecifiedLineTradeAgreement>
<ram:NetPriceProductTradePrice>
<ram:ChargeAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.currency.round(line.unit_price), 'f')}</ram:ChargeAmount>
<ram:ChargeAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.currency.round(line.unit_price).normalize(), 'f')}</ram:ChargeAmount>
</ram:NetPriceProductTradePrice>
</ram:SpecifiedLineTradeAgreement>
<ram:SpecifiedLineTradeDelivery>
<ram:BilledQuantity py:attrs="{'unitCode': line.unit.unece_code} if line.unit and line.unit.unece_code else {}">${format(abs(Decimal(str(line.quantity)).normalize()), 'f')}</ram:BilledQuantity>
<ram:BilledQuantity py:attrs="{'unitCode': line.unit.unece_code} if line.unit and line.unit.unece_code else {}">${format(abs(Decimal(str(line.quantity))), 'f')}</ram:BilledQuantity>
</ram:SpecifiedLineTradeDelivery>
<ram:SpecifiedLineTradeSettlement>
<py:for each="tax in line.invoice_taxes">
${TradeTax(tax.tax)}
</py:for>
<ram:SpecifiedTradeSettlementLineMonetarySummation>
<ram:LineTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(line.amount * this.type_sign, 'f')}</ram:LineTotalAmount>
<ram:LineTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((line.amount * this.type_sign).normalize(), 'f')}</ram:LineTotalAmount>
</ram:SpecifiedTradeSettlementLineMonetarySummation>
</ram:SpecifiedLineTradeSettlement>
</ram:IncludedSupplyChainTradeLineItem>
@@ -158,14 +158,14 @@ this repository contains the full copyright notices and license terms. -->
<ram:DueDateDateTime>
${DateTime(line.maturity_date)}
</ram:DueDateDateTime>
<ram:PartialPaymentAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((line.amount_second_currency or (line.debit - line.credit)) * this.type_sign, 'f')}</ram:PartialPaymentAmount>
<ram:PartialPaymentAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(((line.amount_second_currency or (line.debit - line.credit)) * this.type_sign).normalize(), 'f')}</ram:PartialPaymentAmount>
</ram:SpecifiedTradePaymentTerms>
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
<ram:LineTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.untaxed_amount * this.type_sign, 'f')}</ram:LineTotalAmount>
<ram:TaxBasisTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.untaxed_amount * this.type_sign, 'f')}</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.tax_amount * this.type_sign, 'f')}</ram:TaxTotalAmount>
<ram:GrandTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.total_amount * this.type_sign, 'f')}</ram:GrandTotalAmount>
<ram:DuePayableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format(this.invoice.amount_to_pay * this.type_sign, 'f')}</ram:DuePayableAmount>
<ram:LineTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((this.invoice.untaxed_amount * this.type_sign).normalize(), 'f')}</ram:LineTotalAmount>
<ram:TaxBasisTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((this.invoice.untaxed_amount * this.type_sign).normalize(), 'f')}</ram:TaxBasisTotalAmount>
<ram:TaxTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((this.invoice.tax_amount * this.type_sign).normalize(), 'f')}</ram:TaxTotalAmount>
<ram:GrandTotalAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((this.invoice.total_amount * this.type_sign).normalize(), 'f')}</ram:GrandTotalAmount>
<ram:DuePayableAmount py:attrs="{'currencyID': this.invoice.currency.code}">${format((this.invoice.amount_to_pay * this.type_sign).normalize(), 'f')}</ram:DuePayableAmount>
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
</ram:ApplicableHeaderTradeSettlement>
</rsm:SupplyChainTradeTransaction>
+31 -40
View File
@@ -395,15 +395,12 @@ class Party(
else:
for country in eu_vat.guess_country(text):
if 'eu_vat' in identifier_types:
code = country + text
if eu_vat.is_valid(code):
code = eu_vat.compact(code)
add('eu_vat', code)
code = eu_vat.compact(country + text)
add('eu_vat', code)
elif f'{country}_vat' in identifier_types:
vat = get_cc_module(country, 'vat')
if vat.is_valid(text):
code = vat.compact(text)
add(f'{country}_vat', code)
code = vat.compact(text)
add(f'{country}_vat', code)
return result
@classmethod
@@ -916,20 +913,18 @@ class Identifier(sequence_ordered(), DeactivableMixin, ModelSQL, ModelView):
@fields.depends('type', 'code')
def on_change_with_code(self):
code = self.code
if code and self.type and '_' in self.type:
if self.type and '_' in self.type:
if module := get_cc_module(*self.type.split('_', 1)):
if (hasattr(module, 'is_valid')
and module.is_valid(code)):
if hasattr(module, 'compact'):
try:
code = module.compact(code)
except stdnum.exceptions.ValidationError:
pass
if hasattr(module, 'format'):
try:
code = module.format(code)
except stdnum.exceptions.ValidationError:
pass
if hasattr(module, 'compact'):
try:
code = module.compact(code)
except stdnum.exceptions.ValidationError:
pass
if hasattr(module, 'format'):
try:
code = module.format(code)
except stdnum.exceptions.ValidationError:
pass
return code
def pre_validate(self):
@@ -960,18 +955,16 @@ class Identifier(sequence_ordered(), DeactivableMixin, ModelSQL, ModelView):
if ((type := values.get('type')) and '_' in type
and (code := values.get('code'))):
if module := get_cc_module(*type.split('_', 1)):
if (hasattr(module, 'is_valid')
and module.is_valid(code)):
if hasattr(module, 'format'):
try:
values['code'] = module.format(code)
except stdnum.exceptions.ValidationError:
pass
if hasattr(module, 'compact'):
try:
values['code_compact'] = module.compact(code)
except stdnum.exceptions.ValidationError:
pass
if hasattr(module, 'format'):
try:
values['code'] = module.format(code)
except stdnum.exceptions.ValidationError:
pass
if hasattr(module, 'compact'):
try:
values['code_compact'] = module.compact(code)
except stdnum.exceptions.ValidationError:
pass
return values
def compute_fields(self, field_names=None):
@@ -981,14 +974,12 @@ class Identifier(sequence_ordered(), DeactivableMixin, ModelSQL, ModelView):
code_compact = getattr(self, 'code_compact', None)
if (type := getattr(self, 'type', None)) and '_' in type and code:
if module := get_cc_module(*type.split('_', 1)):
if (hasattr(module, 'is_valid')
and module.is_valid(code)):
if hasattr(module, 'format'):
code = module.format(code)
if hasattr(module, 'compact'):
code_compact = module.compact(code)
else:
code_compact = code
if hasattr(module, 'format'):
code = module.format(code)
if hasattr(module, 'compact'):
code_compact = module.compact(code)
else:
code_compact = code
if getattr(self, 'code', None) != code:
values['code'] = code
if getattr(self, 'code_compact', None) != code_compact:
+11 -13
View File
@@ -470,7 +470,7 @@ class Production(
for input_ in self.inputs:
if input_.state == 'cancelled':
continue
cost_price = input_.get_cost_price() or 0
cost_price = input_.get_cost_price()
cost += (Decimal(str(input_.internal_quantity)) * cost_price)
return round_price(cost)
@@ -491,7 +491,7 @@ class Production(
product = input_.product
quantity = Uom.compute_qty(
input_.unit, input_.quantity, product.default_uom)
cost += Decimal(str(quantity)) * (product.cost_price or 0)
cost += Decimal(str(quantity)) * product.cost_price
return cost
@dualmethod
@@ -516,20 +516,18 @@ class Production(
for input_ in production.bom.inputs:
quantity = input_.compute_quantity(factor)
product = input_.product
for line, quantity in input_.lines_for_quantity(quantity):
move = production._move(
'input', product, input_.unit, quantity)
move.planned_date = input_date
to_save.append(input_.prepare_move(production, move))
move = production._move(
'input', product, input_.unit, quantity)
move.planned_date = input_date
to_save.append(input_.prepare_move(production, move))
for output in production.bom.outputs:
quantity = output.compute_quantity(factor)
product = output.product
for line, quantity in output.lines_for_quantity(quantity):
move = production._move(
'output', product, output.unit, quantity)
move.planned_date = output_date
to_save.append(output.prepare_move(production, move))
move = production._move(
'output', product, output.unit, quantity)
move.planned_date = output_date
to_save.append(output.prepare_move(production, move))
Move.save(to_save)
@classmethod
@@ -566,7 +564,7 @@ class Production(
for input_ in production.inputs:
if input_.state == 'cancelled':
continue
cost_price = input_.get_cost_price() or 0
cost_price = input_.get_cost_price()
input_quantities[input_.product] += (
Decimal(str(input_.internal_quantity)))
input_costs[input_.product] += (
+5 -9
View File
@@ -322,10 +322,8 @@ class Move(Workflow, ModelSQL, ModelView):
()),
],
states={
'invisible': (
~Eval('unit_price_required', False)
& (Eval('unit_price', None) == None)), # noqa: E711
'required': Eval('unit_price_required', False),
'invisible': ~Eval('unit_price_required'),
'required': Bool(Eval('unit_price_required')),
'readonly': Eval('state') != 'draft',
})
unit_price_company = fields.Function(
@@ -348,7 +346,7 @@ class Move(Workflow, ModelSQL, ModelView):
()),
],
states={
'invisible': ~Eval('cost_price_required', False),
'invisible': ~Eval('cost_price_required'),
'required': (
(Eval('state') == 'done')
& Eval('cost_price_required', False)),
@@ -372,10 +370,8 @@ class Move(Workflow, ModelSQL, ModelView):
()),
],
states={
'invisible': (
~Eval('unit_price_required')
& (Eval('currency', None) == None)), # noqa: E711
'required': Eval('unit_price_required', False),
'invisible': ~Eval('unit_price_required'),
'required': Bool(Eval('unit_price_required')),
'readonly': Eval('state') != 'draft',
},
help="The currency in which the unit price is specified.")
+3 -3
View File
@@ -154,13 +154,13 @@ class _InventoryMixin:
output_clause = (
(from_location.left >= left) & (from_location.right <= right))
start_quantity = Sum(
move.internal_quantity * Case((output_clause, -1), else_=1),
move.quantity * Case((output_clause, -1), else_=1),
filter_=(move_date < from_date))
input_quantity = Sum(
move.internal_quantity,
move.quantity,
filter_=input_clause & (move_date >= from_date))
output_quantity = Sum(
move.internal_quantity,
move.quantity,
filter_=output_clause & (move_date >= from_date))
date_column = Greatest(move_date, from_date)
@@ -50,8 +50,6 @@ Get currency::
Create product::
>>> unit, = ProductUom.find([('name', '=', 'Unit')])
>>> box2, = unit.duplicate(default={'factor': 2, 'rate': .5})
>>> box10, = unit.duplicate(default={'factor': 10, 'rate': .1})
>>> template = ProductTemplate()
>>> template.name = 'Product'
@@ -98,8 +96,8 @@ Fill warehouse::
>>> move.product = product
>>> move.from_location = storage_loc
>>> move.to_location = customer_loc
>>> move.unit = box2
>>> move.quantity = 1
>>> move.unit = unit
>>> move.quantity = 2
>>> move.effective_date = dt.date(2025, 1, 10)
>>> move.unit_price = Decimal('20.0000')
>>> move.currency = currency
@@ -113,8 +111,7 @@ Forecast some moves::
>>> move.product = product
>>> move.from_location = supplier_loc
>>> move.to_location = storage_loc
>>> move.unit = box10
>>> move.quantity = 1
>>> move.quantity = 10
>>> move.effective_date = dt.date(2025, 1, 5)
>>> move.unit_price = Decimal('10.0000')
>>> move.currency = currency
+2 -10
View File
@@ -281,18 +281,10 @@ class CreateDPDShipping(Wizard):
cm3 = UoM(ModelData.get_id('product', 'uom_cubic_centimeter'))
kg = UoM(ModelData.get_id('product', 'uom_kilogram'))
volume = sum(
UoM.compute_qty(
p.volume_uom, p.total_volume, shipment.volume_uom, round=False)
for p in shipment.root_packages)
volume = round(UoM.compute_qty(
shipment.volume_uom, volume, cm3, round=False))
weight = sum(
UoM.compute_qty(
p.weight_uom, p.total_weight, shipment.weight_uom, round=False)
for p in shipment.root_packages)
shipment.volume_uom, shipment.volume, cm3, round=False))
weight = round(UoM.compute_qty(
shipment.weight_uom, weight, kg, round=False), 2)
shipment.weight_uom, shipment.weight, kg, round=False), 2)
return {
'generalShipmentData': {
'identificationNumber': shipment.number,
@@ -136,9 +136,7 @@ Create Package Type::
... name='Box',
... length=10, length_uom=cm,
... height=8, height_uom=cm,
... width=5, width_uom=cm,
... packaging_weight=50,
... packaging_weight_uom=g)
... width=5, width_uom=cm)
>>> box.save()
Create a DPD Carrier and the related credential::
+4 -11
View File
@@ -89,16 +89,13 @@
function getScrollableAncestors(el) {
let ancestors = [];
let parent = el.parentElement;
while (parent && (parent !== document.body ||
!parent.classList.contains('modal'))) {
while (parent && parent !== document.body) {
if (isScrollable(parent)) {
ancestors.push(parent);
}
parent = parent.parentElement;
}
if (parent && !parent.classList.contains('modal')) {
ancestors.push(window);
}
ancestors.push(window);
return ancestors;
}
@@ -2981,13 +2978,9 @@
return ((a.isDate == b.isDate) &&
(a.isDateTime == b.isDateTime) &&
(a.valueOf() == b.valueOf()));
} else if ((a instanceof Number) || (b instanceof Number)) {
return (Number(a) === Number(b));
} else {
if (a instanceof Number) {
a = a.valueOf();
}
if (b instanceof Number) {
b = b.valueOf();
}
return (a === b);
}
};
+3 -5
View File
@@ -1102,13 +1102,11 @@
width = column.col.data('default-width');
}
if (width && width.endsWith('%')) {
// Reverse the calculation from _set_column_width
let factor = 1;
width = parseInt(width.slice(0, -1), 10) / 100;
if (column.attributes.expand) {
factor += parseInt(column.attributes.expand, 10);
width /= parseInt(column.attributes.expand, 10);
}
width = parseInt(width.slice(0, -1), 10);
width = `${width / 100 / factor}em`;
width = `${width}em`;
}
min_width.push(width);
column.col.sao_show();
-38
View File
@@ -2969,44 +2969,6 @@
var now = new Date();
[
[[['x', '=', 42]], {'x': 42}, true],
[[['x', '=', 42]], {'x': new Number(42)}, true],
[[['x', '=', 42]], {'x': 0}, false],
[[['x', '=', 42]], {'x': new Number(0)}, false],
[[['x', '=', 42]], {'x': null}, false],
[[['x', '=', new Number(42)]], {'x': 42}, true],
[[['x', '=', new Number(42)]], {'x': new Number(42)}, true],
[[['x', '=', new Number(42)]], {'x': 0}, false],
[[['x', '=', new Number(42)]], {'x': new Number(0)}, false],
[[['x', '=', new Number(42)]], {'x': null}, false],
[[['x', '=', 0]], {'x': 0}, true],
[[['x', '=', 0]], {'x': new Number(0)}, true],
[[['x', '=', 0]], {'x': null}, false],
[[['x', '=', new Number(0)]], {'x': 0}, true],
[[['x', '=', new Number(0)]], {'x': new Number(0)}, true],
[[['x', '=', new Number(0)]], {'x': null}, false],
[[['x', '=', null]], {'x': 0}, false],
[[['x', '=', null]], {'x': new Number(0)}, false],
[[['x', '=', null]], {'x': null}, true],
[[['x', '!=', 42]], {'x': 42}, false],
[[['x', '!=', 42]], {'x': new Number(42)}, false],
[[['x', '!=', 42]], {'x': 0}, true],
[[['x', '!=', 42]], {'x': new Number(0)}, true],
[[['x', '!=', 42]], {'x': null}, true],
[[['x', '!=', new Number(42)]], {'x': 42}, false],
[[['x', '!=', new Number(42)]], {'x': new Number(42)}, false],
[[['x', '!=', new Number(42)]], {'x': 0}, true],
[[['x', '!=', new Number(42)]], {'x': new Number(0)}, true],
[[['x', '!=', new Number(42)]], {'x': null}, true],
[[['x', '!=', 0]], {'x': 0}, false],
[[['x', '!=', 0]], {'x': new Number(0)}, false],
[[['x', '!=', 0]], {'x': null}, true],
[[['x', '!=', new Number(0)]], {'x': 0}, false],
[[['x', '!=', new Number(0)]], {'x': new Number(0)}, false],
[[['x', '!=', new Number(0)]], {'x': null}, true],
[[['x', '!=', null]], {'x': 0}, true],
[[['x', '!=', null]], {'x': new Number(0)}, true],
[[['x', '!=', null]], {'x': null}, false],
[[['x', '>', 5]], {'x': 6}, true],
[[['x', '>', 5]], {'x': 4}, false],
[[['x', '>', null]], {'x': today}, false],
+1 -4
View File
@@ -46,7 +46,4 @@ if db_names:
for thread in threads:
thread.join()
if len(threads := threading.enumerate()) != 1:
raise RuntimeError(
f"There are {len(threads)} threads running after initializing"
" the Pool")
assert len(threads := threading.enumerate()) == 1, f"len({threads}) != 1"
+1 -3
View File
@@ -256,8 +256,6 @@ class MemoryCache(BaseCache):
@classmethod
def sync(cls, transaction):
if not Pool().ready:
return
if cls._clean_last is None:
cls._clean_last = dt.datetime.now()
return
@@ -300,7 +298,7 @@ class MemoryCache(BaseCache):
cls._clean_last = dt.datetime.now()
def sync_since(self, value):
return self._clean_last is not None and self._clean_last > value
return self._clean_last > value
@classmethod
def commit(cls, transaction):
+1 -1
View File
@@ -104,7 +104,7 @@ class TrytonConfigParser(configparser.ConfigParser):
self.add_section('bus')
self.set('bus', 'allow_subscribe', 'False')
self.set('bus', 'long_polling_timeout', str(5 * 60))
self.set('bus', 'cache_timeout', str(5 * 60))
self.set('bus', 'cache_timeout', '5')
self.set('bus', 'select_timeout', '5')
self.add_section('report')
self.add_section('html')
+4 -9
View File
@@ -345,11 +345,7 @@ class ActionMixin(ModelSQL):
action = fields.Many2One(
'ir.action', "Action",
required=True, ondelete='CASCADE',
states={
'required': Eval('id', -1) >= 0,
'readonly': Eval('id', -1) >= 0,
})
required=True, readonly=True, ondelete='CASCADE')
@classmethod
def __setup__(cls):
@@ -460,9 +456,8 @@ class ActionMixin(ModelSQL):
values = values.copy()
for field in values:
if field in Action._fields:
if field != 'action':
action_values[field] = values[field]
elif hasattr(getattr(cls, field), 'set'):
action_values[field] = values[field]
if hasattr(getattr(cls, field), 'set'):
later[field] = values[field]
for field in later:
del values[field]
@@ -473,7 +468,7 @@ class ActionMixin(ModelSQL):
if database.nextid(transaction.connection, cls._table):
database.setnextid(transaction.connection, cls._table,
database.currid(transaction.connection, Action._table))
if not values.get('action'):
if 'action' not in values:
action, = Action.create([action_values])
values['action'] = action.id
else:
+1 -1
View File
@@ -464,7 +464,7 @@ class Report(URLMixin, PoolBase):
time.sleep(0.02 * (retry - count))
try:
subprocess.run(args, timeout=timeout, check=True)
except (subprocess.SubprocessError, OSError):
except subprocess.CalledProcessError:
if count:
continue
logger.error(
-57
View File
@@ -884,63 +884,6 @@ class DomainInversionTestCase(TestCase):
unique_value(domain, single_value=False), (False, None, None))
def test_evaldomain(self):
domain = [['x', '=', 42]]
self.assertTrue(eval_domain(domain, {'x': 42}))
self.assertTrue(eval_domain(domain, {'x': Decimal('42')}))
self.assertFalse(eval_domain(domain, {'x': 0}))
self.assertFalse(eval_domain(domain, {'x': Decimal('0')}))
self.assertFalse(eval_domain(domain, {'x': None}))
domain = [['x', '=', Decimal('42')]]
self.assertTrue(eval_domain(domain, {'x': 42}))
self.assertTrue(eval_domain(domain, {'x': Decimal('42')}))
self.assertFalse(eval_domain(domain, {'x': 0}))
self.assertFalse(eval_domain(domain, {'x': Decimal('0')}))
self.assertFalse(eval_domain(domain, {'x': None}))
domain = [['x', '=', 0]]
self.assertTrue(eval_domain(domain, {'x': 0}))
self.assertTrue(eval_domain(domain, {'x': Decimal('0')}))
self.assertFalse(eval_domain(domain, {'x': None}))
domain = [['x', '=', Decimal('0')]]
self.assertTrue(eval_domain(domain, {'x': 0}))
self.assertTrue(eval_domain(domain, {'x': Decimal('0')}))
self.assertFalse(eval_domain(domain, {'x': None}))
domain = [['x', '=', None]]
self.assertFalse(eval_domain(domain, {'x': 0}))
self.assertFalse(eval_domain(domain, {'x': Decimal('0')}))
self.assertTrue(eval_domain(domain, {'x': None}))
domain = [['x', '!=', 42]]
self.assertFalse(eval_domain(domain, {'x': 42}))
self.assertFalse(eval_domain(domain, {'x': Decimal('42')}))
self.assertTrue(eval_domain(domain, {'x': Decimal('0')}))
self.assertTrue(eval_domain(domain, {'x': None}))
domain = [['x', '!=', Decimal('42')]]
self.assertFalse(eval_domain(domain, {'x': 42}))
self.assertFalse(eval_domain(domain, {'x': Decimal('42')}))
self.assertTrue(eval_domain(domain, {'x': Decimal('0')}))
self.assertTrue(eval_domain(domain, {'x': None}))
domain = [['x', '!=', 0]]
self.assertFalse(eval_domain(domain, {'x': 0}))
self.assertFalse(eval_domain(domain, {'x': Decimal('0')}))
self.assertTrue(eval_domain(domain, {'x': None}))
domain = [['x', '!=', Decimal('0')]]
self.assertFalse(eval_domain(domain, {'x': 0}))
self.assertFalse(eval_domain(domain, {'x': Decimal('0')}))
self.assertTrue(eval_domain(domain, {'x': None}))
domain = [['x', '!=', None]]
self.assertTrue(eval_domain(domain, {'x': 0}))
self.assertTrue(eval_domain(domain, {'x': Decimal('0')}))
self.assertFalse(eval_domain(domain, {'x': None}))
domain = [['x', '>', 5]]
self.assertTrue(eval_domain(domain, {'x': 6}))
self.assertFalse(eval_domain(domain, {'x': 4}))