From 26f43c243894d46647a869dfb708b242d499180e Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Thu, 28 May 2026 13:34:56 +0200 Subject: [PATCH] Template Melya --- .../.~lock.invoice_melya.fodt# | 1 + modules/account_invoice/invoice_melya.fodt | 9 ++- modules/purchase_trade/invoice.py | 63 +++++++++++++++++ modules/purchase_trade/sale.py | 55 ++++++++++++--- modules/purchase_trade/tests/test_module.py | 69 +++++++++++++++++++ modules/sale/sale_melya.fodt | 2 + 6 files changed, 184 insertions(+), 15 deletions(-) create mode 100644 modules/account_invoice/.~lock.invoice_melya.fodt# diff --git a/modules/account_invoice/.~lock.invoice_melya.fodt# b/modules/account_invoice/.~lock.invoice_melya.fodt# new file mode 100644 index 0000000..48c5307 --- /dev/null +++ b/modules/account_invoice/.~lock.invoice_melya.fodt# @@ -0,0 +1 @@ +,PC_LO/baron,PC_LO,28.05.2026 13:23,file:///C:/Users/baron/AppData/Roaming/LibreOffice/4; \ No newline at end of file diff --git a/modules/account_invoice/invoice_melya.fodt b/modules/account_invoice/invoice_melya.fodt index 57196b2..6321f9e 100644 --- a/modules/account_invoice/invoice_melya.fodt +++ b/modules/account_invoice/invoice_melya.fodt @@ -1584,12 +1584,11 @@ Payment terms: <invoice.report_payment_description or ''>  - Bank: UBS SWITZERLAND AG - Case Postale - CH-1211 Genève 2 + <if test="invoice.report_melya_bank_name">Bank: <invoice.report_melya_bank_name></if> + <for each="line in invoice.report_melya_bank_address.splitlines()"><line></for> - IBAN : CH36 0021 5215 2487 7461 D - SwifT Code: UBSWCHZH80A + <if test="invoice.report_melya_bank_iban">IBAN : <invoice.report_melya_bank_iban></if> + <if test="invoice.report_melya_bank_swift">SwifT Code: <invoice.report_melya_bank_swift></if> diff --git a/modules/purchase_trade/invoice.py b/modules/purchase_trade/invoice.py index d109d0a..fac53a3 100644 --- a/modules/purchase_trade/invoice.py +++ b/modules/purchase_trade/invoice.py @@ -644,11 +644,74 @@ class Invoice(metaclass=PoolMeta): bank = getattr(account, 'bank', None) if account else None return getattr(bank, 'bic', None) or '' + @staticmethod + def _get_report_bank_address(account): + bank = getattr(account, 'bank', None) if account else None + party = getattr(bank, 'party', None) if bank else None + address_get = getattr(party, 'address_get', None) if party else None + if callable(address_get): + return address_get() + return None + + @staticmethod + def _get_report_bank_party_name(account): + bank = getattr(account, 'bank', None) if account else None + party = getattr(bank, 'party', None) if bank else None + address = Invoice._get_report_bank_address(account) + return ( + getattr(address, 'party_full_name', None) + or getattr(address, 'party_name', None) + or getattr(party, 'rec_name', None) + or getattr(bank, 'rec_name', None) + or '') + + @staticmethod + def _get_report_bank_address_lines(account): + address = Invoice._get_report_bank_address(account) + full_address = getattr(address, 'full_address', None) if address else '' + if not full_address and address: + city_line = ' '.join(filter(None, [ + getattr(address, 'postal_code', None), + getattr(address, 'city', None), + ])) + full_address = '\n'.join(filter(None, [ + getattr(address, 'name', None), + getattr(address, 'street', None), + city_line, + ])) + return '\n'.join( + line for line in (full_address or '').splitlines() + if line.strip()) + @staticmethod def _format_report_payment_amount(value): amount = Decimal(str(value or 0)).quantize(Decimal('0.01')) return format(amount, 'f') + def _get_report_melya_bank_account(self): + sale = self._get_report_deal_sale() + return getattr(sale, 'our_bank_account', None) if sale else None + + @property + def report_melya_bank_name(self): + return self._get_report_bank_party_name( + self._get_report_melya_bank_account()) + + @property + def report_melya_bank_address(self): + return self._get_report_bank_address_lines( + self._get_report_melya_bank_account()) + + @property + def report_melya_bank_iban(self): + return self._get_report_bank_account_number( + self._get_report_melya_bank_account()) + + @property + def report_melya_bank_swift(self): + return self._get_report_bank_swift( + self._get_report_melya_bank_account()) + @property def _report_payment_order_company_account(self): return self._get_report_bank_account(getattr(self.company, 'party', None)) diff --git a/modules/purchase_trade/sale.py b/modules/purchase_trade/sale.py index e8baa34..155e886 100755 --- a/modules/purchase_trade/sale.py +++ b/modules/purchase_trade/sale.py @@ -784,16 +784,51 @@ class Sale(metaclass=PoolMeta): @property def report_deal(self): - if self.lines and self.lines[0].lots and len(self.lines[0].lots) > 1: - purchase = getattr(getattr(self.lines[0].lots[1], 'line', None), - 'purchase', None) - purchase_number = getattr(purchase, 'number', None) - purchase_number = self._format_report_deal_number( - purchase_number, 'P') - sale_number = self._format_report_deal_number(self.number, 'S') - return ' '.join( - number for number in [purchase_number, sale_number] if number) - return '' + purchase = self._get_report_deal_purchase() + purchase_number = self._format_report_deal_number( + getattr(purchase, 'number', None), 'P') + sale_number = self._format_report_deal_number( + getattr(self, 'number', None), 'S') + return ' '.join( + number for number in [purchase_number, sale_number] if number) + + def _get_report_deal_purchase(self): + lots = [] + for line in getattr(self, 'lines', []) or []: + lots.extend(getattr(line, 'lots', []) or []) + + for lot in lots: + purchase = getattr(getattr(lot, 'line', None), 'purchase', None) + if purchase: + return purchase + + if not lots: + return None + + LotQt = Pool().get('lot.qt') + for lot in lots: + lot_ids = [] + lot_id = getattr(lot, 'id', None) + if lot_id: + lot_ids.append(lot_id) + get_vlot_s = getattr(lot, 'getVlot_s', None) + if get_vlot_s: + virtual_lot = get_vlot_s() + virtual_lot_id = getattr(virtual_lot, 'id', None) + if virtual_lot_id: + lot_ids.append(virtual_lot_id) + for lot_id in lot_ids: + lot_qts = LotQt.search([ + ('lot_s', '=', lot_id), + ('lot_p', '>', 0), + ], limit=1) + for lot_qt in lot_qts: + purchase = getattr( + getattr(getattr(lot_qt, 'lot_p', None), 'line', None), + 'purchase', None) + if purchase: + return purchase + return None @staticmethod def _format_report_deal_number(number, prefix): diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py index dca4749..9c11ebf 100644 --- a/modules/purchase_trade/tests/test_module.py +++ b/modules/purchase_trade/tests/test_module.py @@ -3259,6 +3259,75 @@ class PurchaseTradeTestCase(ModuleTestCase): self.assertEqual(invoice.report_contract_number, 'P-12/S-34') + def test_invoice_melya_bank_uses_sale_our_bank_account(self): + 'invoice_melya bank block uses the sale company bank account' + Invoice = Pool().get('account.invoice') + + address = Mock( + party_full_name='UBS SWITZERLAND AG', + full_address='Case Postale\nCH-1211 Geneve 2', + ) + party = Mock(rec_name='UBS') + party.address_get.return_value = address + bank = Mock(party=party, bic='UBSWCHZH80A') + account = Mock( + bank=bank, + numbers=[Mock(type='iban', number='CH36 0021 5215 2487 7461 D')], + ) + sale = Mock(our_bank_account=account) + + invoice = Invoice() + invoice._get_report_deal_sale = Mock(return_value=sale) + + self.assertEqual(invoice.report_melya_bank_name, 'UBS SWITZERLAND AG') + self.assertEqual( + invoice.report_melya_bank_address, + 'Case Postale\nCH-1211 Geneve 2') + self.assertEqual( + invoice.report_melya_bank_iban, + 'CH36 0021 5215 2487 7461 D') + self.assertEqual(invoice.report_melya_bank_swift, 'UBSWCHZH80A') + + def test_sale_report_deal_uses_purchase_and_sale_numbers(self): + 'sale deal number includes the linked purchase number' + Sale = Pool().get('sale.sale') + + purchase = Mock(number='12') + lot = Mock(line=Mock(purchase=purchase)) + sale = Sale() + sale.number = '88' + sale.lines = [Mock(lots=[lot])] + + self.assertEqual(sale.report_deal, 'P-12 S-88') + self.assertEqual(sale.report_melya_proforma_number, 'P-12 S-88') + + def test_sale_report_deal_falls_back_to_lot_qt_matching(self): + 'sale deal number finds purchase through lot.qt matching' + Sale = Pool().get('sale.sale') + + class SaleLot: + id = 99 + line = None + + purchase = Mock(number='12') + lot_qt_model = Mock() + lot_qt_model.search.return_value = [ + Mock(lot_p=Mock(line=Mock(purchase=purchase)))] + + sale = Sale() + sale.number = '88' + sale.lines = [Mock(lots=[SaleLot()])] + + with patch('trytond.modules.purchase_trade.sale.Pool') as PoolMock: + PoolMock.return_value.get.return_value = lot_qt_model + + self.assertEqual(sale.report_deal, 'P-12 S-88') + + lot_qt_model.search.assert_called_once_with([ + ('lot_s', '=', 99), + ('lot_p', '>', 0), + ], limit=1) + def test_contract_factory_uses_one_line_per_selected_source(self): 'matched multi-lot contract creation keeps one generated line per source lot' contract_detail = Mock(quantity=Decimal('2000')) diff --git a/modules/sale/sale_melya.fodt b/modules/sale/sale_melya.fodt index 33fa0db..b723ab6 100644 --- a/modules/sale/sale_melya.fodt +++ b/modules/sale/sale_melya.fodt @@ -662,9 +662,11 @@ + +