first commit

This commit is contained in:
root
2026-03-14 09:42:12 +00:00
commit 0adbd20c2c
10991 changed files with 1646955 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

View File

@@ -0,0 +1,48 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import os
import genshi
import genshi.template
from trytond.modules.account_payment_sepa import payment as sepa_payment
from trytond.pool import PoolMeta
class Journal(metaclass=PoolMeta):
__name__ = 'account.payment.journal'
@classmethod
def __setup__(cls):
super().__setup__()
payable_flavor_cfonb = ('pain.001.001.03-cfonb',
'pain.001.001.03 CFONB')
receivable_flavor_cfonb = ('pain.008.001.02-cfonb',
'pain.008.001.02 CFONB')
for flavor, field in [
(payable_flavor_cfonb, cls.sepa_payable_flavor),
(receivable_flavor_cfonb, cls.sepa_receivable_flavor),
]:
if flavor not in field.selection:
field.selection.append(flavor)
loader = genshi.template.TemplateLoader([
os.path.join(os.path.dirname(__file__), 'template'),
os.path.join(
os.path.dirname(
sepa_payment.__file__), 'template'),
], auto_reload=True)
class Group(metaclass=PoolMeta):
__name__ = 'account.payment.group'
def get_sepa_template(self):
if (self.kind == 'payable'
and self.journal.sepa_payable_flavor.endswith('-cfonb')):
return loader.load('%s.xml' % self.journal.sepa_payable_flavor)
if (self.kind == 'receivable'
and self.journal.sepa_receivable_flavor.endswith('-cfonb')):
return loader.load('%s.xml' % self.journal.sepa_receivable_flavor)
return super().get_sepa_template()

View File

@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<py:strip xmlns:py="http://genshi.edgewall.org/">
<!-- CFONB forbid PstlAdr -->
<py:def function="PartyIdentification(party, id=None, with_name=True)">
<!-- EPC limits to 70 instead of 140 -->
<Nm py:if="with_name">${party.name[:70]}</Nm>
<Id py:if="id">
<py:with vars="identifier = party.get_sepa_identifier(id)">
<OrgId py:if="identifier['Type'] == 'OrgId'">
<BICOrBEI py:if="identifier.get('BICOrBEI')">${identifier['BICOrBEI']}</BICOrBEI>
<Othr py:if="identifier.get('Id')">
<Id>${identifier['Id']}</Id>
<SchmeNm py:if="identifier.get('SchmeNm')">
<Cd py:if="identifier['SchmeNm'].get('Cd')">${identifier['SchmeNm']['Cd']}</Cd>
<Prtry py:if="identifier['SchmeNm'].get('Prtry')">${identifier['SchmeNm']['Cd']}</Prtry>
</SchmeNm>
<Issr py:if="identifier.get('Issr')">${identifier['Issr']}</Issr>
</Othr>
</OrgId>
<PrvtId py:if="identifier['Type'] == 'PrvtId'">
<DtAndPlcOfBirth py:if="identifier.get('DtAndPlcOfBirth')">
<BirthDt>${identifier['DtAndPlcOfBirth']['BirthDt'].isoformat()}</BirthDt>
<PrvcOfBirth py:if="identifier['DtAndPlcOfBirth'].get('PrvcOfBirth')">${identifier['DtAndPlcOfBirth']['PrvcOfBirth']}</PrvcOfBirth>
<CityOfBirth>${identifier['DtAndPlcOfBirth']['CityOfBirth']}</CityOfBirth>
<CtryOfBirth>${identifier['DtAndPlcOfBirth']['CtryOfBirth']}</CtryOfBirth>
</DtAndPlcOfBirth>
<Othr py:if="identifier.get('Id')">
<Id>${identifier['Id']}</Id>
<SchmeNm py:if="identifier.get('SchmeNm')">
<Cd py:if="identifier['SchmeNm'].get('Cd')">${identifier['SchmeNm']['Cd']}</Cd>
<Prtry py:if="identifier['SchmeNm'].get('Prtry')">${identifier['SchmeNm']['Prtry']}</Prtry>
</SchmeNm>
<Issr py:if="identifier.get('Issr')">${identifier['Issr']}</Issr>
</Othr>
</PrvtId>
</py:with>
</Id>
<!-- CtryOfRes -->
<!-- CtctDtls -->
</py:def>
</py:strip>

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/">
<xi:include href="base.xml"/>
<xi:include href="base-cfonb.xml"/>
<!-- version 3 uses BIC instead of BICFI -->
<py:def function="FinancialInstitution(bank, only_bic=False)">
<FinInstnId>
<BIC py:if="bank.bic">${bank.bic}</BIC>
<py:if test="not only_bic">
<!-- ClrSysMmbId -->
<Nm>${bank.party.name[:140]}</Nm>
</py:if>
<Othr py:if="not bank.bic">
<Id>NOTPROVIDED</Id>
</Othr>
</FinInstnId>
</py:def>
<CstmrCdtTrfInitn>
<GrpHdr>
<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>${sum(p.amount for p in group.payments)}</CtrlSum>
<InitgPty>
${PartyIdentification(group.sepa_initiating_party)}
</InitgPty>
</GrpHdr>
<PmtInf py:for="key, payments in group.sepa_payments">
<PmtInfId>${group.sepa_group_payment_id(key)[:35]}</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<BtchBookg>${'true' if group.journal.sepa_batch_booking else 'false'}</BtchBookg>
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${sum(p.amount for p in payments)}</CtrlSum>
<PmtTpInf>
<!-- InstrPrty -->
<SvcLvl>
<Cd>SEPA</Cd>
</SvcLvl>
<!-- CtgyPurp -->
</PmtTpInf>
<ReqdExctnDt>${key['date'].isoformat()}</ReqdExctnDt>
<Dbtr>
${PartyIdentification(group.company.party)}
</Dbtr>
<DbtrAcct>
${Account(group.journal.sepa_bank_account_number)}
</DbtrAcct>
<DbtrAgt>
${FinancialInstitution(group.journal.sepa_bank_account_number.account.bank, only_bic=True)}
</DbtrAgt>
<!-- UltmtDbtr -->
<ChrgBr>${group.journal.sepa_charge_bearer}</ChrgBr>
<CdtTrfTxInf py:for="payment in payments">
<PmtId>
<InstrId>${payment.sepa_instruction_id}</InstrId>
<EndToEndId>${payment.sepa_end_to_end_id}</EndToEndId>
</PmtId>
<Amt>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${payment.amount}</InstdAmt>
<!-- EqvtAmt -->
</Amt>
<!-- ChrgBr --> <!-- EPC only at payment information level -->
<!-- UltmtDbtr -->
<!-- IntrmyAgt1 -->
<!-- IntrmyAgt1Acct -->
<CdtrAgt>
${FinancialInstitution(payment.sepa_bank_account_number.account.bank, only_bic=True)}
</CdtrAgt>
<!-- CdtrAgtAcct -->
<Cdtr>
${PartyIdentification(payment.party)}
</Cdtr>
<CdtrAcct>
${Account(payment.sepa_bank_account_number, currency=False)}
</CdtrAcct>
<!-- UltmtCdtr -->
<!-- InstrForCdtrAgt -->
<!-- RgltryRptg -->
<!-- RltdRmtInf -->
<RmtInf py:if="payment.sepa_remittance_information">
<Ustrd>${payment.sepa_remittance_information[:140]}</Ustrd>
</RmtInf>
</CdtTrfTxInf>
</PmtInf>
</CstmrCdtTrfInitn>
</Document>

View File

@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/">
<xi:include href="base.xml"/>
<xi:include href="base-cfonb.xml"/>
<!-- version 2 uses BIC instead of BICFI -->
<py:def function="FinancialInstitution(bank, only_bic=False)">
<FinInstnId>
<BIC py:if="bank.bic">${bank.bic}</BIC>
<py:if test="not only_bic">
<!-- ClrSysMmbId -->
<Nm>${bank.party.name[:140]}</Nm>
<py:with vars="address = bank.party.address_get()">
<PstlAdr py:if="address">
${PostalAddress(address)}
</PstlAdr>
</py:with>
</py:if>
<Othr py:if="not bank.bic">
<Id>NOTPROVIDED</Id>
</Othr>
</FinInstnId>
<!-- BrnchId -->
</py:def>
<CstmrDrctDbtInitn>
<GrpHdr>
<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>${sum(p.amount for p in group.payments)}</CtrlSum>
<InitgPty>
${PartyIdentification(group.sepa_initiating_party)}
</InitgPty>
</GrpHdr>
<PmtInf py:for="key, payments in group.sepa_payments">
<PmtInfId>${group.sepa_group_payment_id(key)[:35]}</PmtInfId>
<PmtMtd>DD</PmtMtd>
<BtchBookg>${'true' if group.journal.sepa_batch_booking else 'false'}</BtchBookg>
<NbOfTxs>${len(payments)}</NbOfTxs>
<CtrlSum>${sum(p.amount for p in payments)}</CtrlSum>
<PmtTpInf>
<SvcLvl>
<Cd>SEPA</Cd>
</SvcLvl>
<LclInstrm>
<Cd>${key['scheme']}</Cd>
</LclInstrm>
<SeqTp>${key['sequence_type']}</SeqTp>
<!-- CtgyPurp -->
</PmtTpInf>
<ReqdColltnDt>${key['date'].isoformat()}</ReqdColltnDt>
<Cdtr>
${PartyIdentification(group.company.party)}
</Cdtr>
<CdtrAcct>
${Account(group.journal.sepa_bank_account_number)}
</CdtrAcct>
<CdtrAgt>
${FinancialInstitution(group.journal.sepa_bank_account_number.account.bank, only_bic=True)}
</CdtrAgt>
<!-- UltmtCdtr -->
<ChrgBr>${group.journal.sepa_charge_bearer}</ChrgBr>
<CdtrSchmeId>
${PartyIdentification(group.company.party, id='eu_at_02', with_name=False)}
</CdtrSchmeId>
<DrctDbtTxInf py:for="payment in payments">
<PmtId>
<InstrId>${payment.sepa_instruction_id}</InstrId>
<EndToEndId>${payment.sepa_end_to_end_id}</EndToEndId>
</PmtId>
<InstdAmt py:attrs="{'Ccy': payment.currency.code}">${payment.amount}</InstdAmt>
<DrctDbtTx>
<MndtRltdInf py:with="mandate = payment.sepa_mandate">
<MndtId>${mandate.identification}</MndtId>
<DtOfSgntr>${mandate.signature_date.isoformat()}</DtOfSgntr>
<!-- AmdmntInd -->
<!-- AmdmntInfDtls -->
</MndtRltdInf>
</DrctDbtTx>
<!-- UltmtCdtr -->
<DbtrAgt>
${FinancialInstitution(payment.sepa_bank_account_number.account.bank, only_bic=True)}
</DbtrAgt>
<!-- DbtrAgtAcct -->
<Dbtr>
${PartyIdentification(payment.party)}
</Dbtr>
<DbtrAcct>
${Account(payment.sepa_bank_account_number, currency=False)}
</DbtrAcct>
<!-- UltmtDbtr -->
<!-- Purp -->
<!-- RgltryRptg -->
<!-- RltdRmtInf -->
<RmtInf py:if="payment.sepa_remittance_information">
<Ustrd>${payment.sepa_remittance_information[:140]}</Ustrd>
</RmtInf>
</DrctDbtTxInf>
</PmtInf>
</CstmrDrctDbtInitn>
</Document>

View File

@@ -0,0 +1,2 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.

View File

@@ -0,0 +1,26 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from trytond.modules.account_payment_sepa.tests import validate_file
from trytond.modules.company.tests import CompanyTestMixin
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
class AccountPaymentSepaCFONBTestCase(CompanyTestMixin, ModuleTestCase):
'Test Account Payment SEPA CFONB module'
module = 'account_payment_sepa_cfonb'
@with_transaction()
def test_pain001_001_03_cfonb(self):
'Test pain.00r.001.03-cfonb xsd validation'
validate_file('pain.001.001.03-cfonb', 'payable',
xsd='pain.001.001.03')
@with_transaction()
def test_pain008_001_02_cfonb(self):
'Test pain.008.001.02-cfonb xsd validation'
validate_file('pain.008.001.02-cfonb', 'receivable',
xsd='pain.008.001.02')
del ModuleTestCase

View File

@@ -0,0 +1,13 @@
[tryton]
version=7.8.0
depends:
account_payment
account_payment_sepa
company
bank
party
[register]
model:
payment.Journal
payment.Group