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 @@
+
+