02.04.26
This commit is contained in:
@@ -243,13 +243,17 @@ Source code: `modules/purchase_trade/sale.py`
|
|||||||
- `report_gross`
|
- `report_gross`
|
||||||
- `report_net`
|
- `report_net`
|
||||||
- `report_qt`
|
- `report_qt`
|
||||||
|
- `report_total_quantity`
|
||||||
|
- `report_quantity_unit_upper`
|
||||||
- `report_nb_bale`
|
- `report_nb_bale`
|
||||||
- `report_deal`
|
- `report_deal`
|
||||||
- `report_packing`
|
- `report_packing`
|
||||||
- `report_price`
|
- `report_price`
|
||||||
|
- `report_price_lines`
|
||||||
- `report_delivery`
|
- `report_delivery`
|
||||||
- `report_payment_date`
|
- `report_payment_date`
|
||||||
- `report_shipment`
|
- `report_shipment`
|
||||||
|
- `report_shipment_periods`
|
||||||
|
|
||||||
Usage typique:
|
Usage typique:
|
||||||
- base de travail pour les templates de type `sale_ict.fodt`
|
- base de travail pour les templates de type `sale_ict.fodt`
|
||||||
|
|||||||
@@ -319,47 +319,107 @@ class Sale(metaclass=PoolMeta):
|
|||||||
def default_tol_min(cls):
|
def default_tol_min(cls):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default_tol_max(cls):
|
def default_tol_max(cls):
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
@property
|
def _get_report_lines(self):
|
||||||
def report_terms(self):
|
return [line for line in self.lines if getattr(line, 'type', None) == 'line']
|
||||||
if self.lines:
|
|
||||||
return self.lines[0].note
|
def _get_report_first_line(self):
|
||||||
else:
|
lines = self._get_report_lines()
|
||||||
return ''
|
if lines:
|
||||||
|
return lines[0]
|
||||||
@property
|
|
||||||
def report_gross(self):
|
@staticmethod
|
||||||
if self.lines:
|
def _format_report_number(value, digits='0.0000', keep_trailing_decimal=False,
|
||||||
return sum([l.get_current_gross_quantity() for l in self.lines[0].lots if l.lot_type == 'physic'])
|
strip_trailing_zeros=True):
|
||||||
else:
|
value = Decimal(str(value or 0)).quantize(Decimal(digits))
|
||||||
return ''
|
text = format(value, 'f')
|
||||||
|
if strip_trailing_zeros:
|
||||||
@property
|
text = text.rstrip('0').rstrip('.')
|
||||||
def report_net(self):
|
if keep_trailing_decimal and '.' not in text:
|
||||||
if self.lines:
|
text += '.0'
|
||||||
return sum([l.get_current_quantity() for l in self.lines[0].lots if l.lot_type == 'physic'])
|
return text or '0'
|
||||||
else:
|
|
||||||
return ''
|
def _format_report_price_words(self, line):
|
||||||
|
if getattr(line, 'linked_price', None):
|
||||||
@property
|
return amount_to_currency_words(line.linked_price, 'USC', 'USC')
|
||||||
def report_qt(self):
|
return amount_to_currency_words(line.unit_price)
|
||||||
if self.lines:
|
|
||||||
return quantity_to_words(self.lines[0].quantity)
|
def _format_report_price_line(self, line):
|
||||||
else:
|
currency = getattr(line, 'linked_currency', None) or self.currency
|
||||||
return ''
|
unit = getattr(line, 'linked_unit', None) or getattr(line, 'unit', None)
|
||||||
|
pricing_text = getattr(line, 'get_pricing_text', '') or ''
|
||||||
@property
|
parts = [
|
||||||
|
(currency.rec_name.upper() if currency and currency.rec_name else '').strip(),
|
||||||
|
self._format_report_number(
|
||||||
|
line.linked_price if getattr(line, 'linked_price', None)
|
||||||
|
else line.unit_price,
|
||||||
|
strip_trailing_zeros=False),
|
||||||
|
'PER',
|
||||||
|
(unit.rec_name.upper() if unit and unit.rec_name else '').strip(),
|
||||||
|
f"({self._format_report_price_words(line)})",
|
||||||
|
]
|
||||||
|
if pricing_text:
|
||||||
|
parts.append(pricing_text)
|
||||||
|
return ' '.join(part for part in parts if part)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def report_terms(self):
|
||||||
|
line = self._get_report_first_line()
|
||||||
|
if line:
|
||||||
|
return line.note
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def report_gross(self):
|
||||||
|
line = self._get_report_first_line()
|
||||||
|
if line:
|
||||||
|
return sum([l.get_current_gross_quantity() for l in line.lots if l.lot_type == 'physic'])
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def report_net(self):
|
||||||
|
line = self._get_report_first_line()
|
||||||
|
if line:
|
||||||
|
return sum([l.get_current_quantity() for l in line.lots if l.lot_type == 'physic'])
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def report_total_quantity(self):
|
||||||
|
lines = self._get_report_lines()
|
||||||
|
if lines:
|
||||||
|
total = sum(Decimal(str(line.quantity or 0)) for line in lines)
|
||||||
|
return self._format_report_number(total, keep_trailing_decimal=True)
|
||||||
|
return '0.0'
|
||||||
|
|
||||||
|
@property
|
||||||
|
def report_quantity_unit_upper(self):
|
||||||
|
line = self._get_report_first_line()
|
||||||
|
if line and line.unit:
|
||||||
|
return line.unit.rec_name.upper()
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def report_qt(self):
|
||||||
|
lines = self._get_report_lines()
|
||||||
|
if lines:
|
||||||
|
total = sum(Decimal(str(line.quantity or 0)) for line in lines)
|
||||||
|
return quantity_to_words(total)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@property
|
||||||
def report_nb_bale(self):
|
def report_nb_bale(self):
|
||||||
text_bale = 'NB BALES: '
|
|
||||||
nb_bale = 0
|
nb_bale = 0
|
||||||
if self.lines:
|
lines = self._get_report_lines()
|
||||||
for line in self.lines:
|
if lines:
|
||||||
|
for line in lines:
|
||||||
if line.lots:
|
if line.lots:
|
||||||
nb_bale += sum([l.lot_qt for l in line.lots if l.lot_type == 'physic'])
|
nb_bale += sum([l.lot_qt for l in line.lots if l.lot_type == 'physic'])
|
||||||
return text_bale + str(int(nb_bale))
|
if nb_bale:
|
||||||
|
return 'NB BALES: ' + str(int(nb_bale))
|
||||||
|
return ''
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def report_crop_name(self):
|
def report_crop_name(self):
|
||||||
@@ -375,29 +435,37 @@ class Sale(metaclass=PoolMeta):
|
|||||||
''
|
''
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def report_packing(self):
|
def report_packing(self):
|
||||||
nb_packing = 0
|
nb_packing = 0
|
||||||
unit = ''
|
unit = ''
|
||||||
if self.lines:
|
lines = self._get_report_lines()
|
||||||
for line in self.lines:
|
if lines:
|
||||||
if line.lots:
|
for line in lines:
|
||||||
nb_packing += sum([l.lot_qt for l in line.lots if l.lot_type == 'physic'])
|
if line.lots:
|
||||||
if len(line.lots)>1:
|
nb_packing += sum([l.lot_qt for l in line.lots if l.lot_type == 'physic'])
|
||||||
unit = line.lots[1].lot_unit.name
|
if len(line.lots)>1:
|
||||||
return str(int(nb_packing)) + unit
|
unit = line.lots[1].lot_unit.name
|
||||||
|
return str(int(nb_packing)) + unit
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def report_price(self):
|
def report_price(self):
|
||||||
if self.lines:
|
line = self._get_report_first_line()
|
||||||
if self.lines[0].price_type == 'priced':
|
if line:
|
||||||
if self.lines[0].linked_price:
|
if line.price_type == 'priced':
|
||||||
return amount_to_currency_words(self.lines[0].linked_price,'USC','USC')
|
if line.linked_price:
|
||||||
|
return amount_to_currency_words(line.linked_price,'USC','USC')
|
||||||
else:
|
else:
|
||||||
return amount_to_currency_words(self.lines[0].unit_price)
|
return amount_to_currency_words(line.unit_price)
|
||||||
elif self.lines[0].price_type == 'basis':
|
elif line.price_type == 'basis':
|
||||||
return amount_to_currency_words(self.lines[0].unit_price) + ' ' + self.lines[0].get_pricing_text
|
return amount_to_currency_words(line.unit_price) + ' ' + line.get_pricing_text
|
||||||
else:
|
return ''
|
||||||
return ''
|
|
||||||
|
@property
|
||||||
|
def report_price_lines(self):
|
||||||
|
lines = self._get_report_lines()
|
||||||
|
if lines:
|
||||||
|
return '\n'.join(self._format_report_price_line(line) for line in lines)
|
||||||
|
return ''
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def report_delivery(self):
|
def report_delivery(self):
|
||||||
@@ -413,20 +481,33 @@ class Sale(metaclass=PoolMeta):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def report_delivery_period_description(self):
|
def report_delivery_period_description(self):
|
||||||
if self.lines and self.lines[0].del_period:
|
line = self._get_report_first_line()
|
||||||
return self.lines[0].del_period.description or ''
|
if line and line.del_period:
|
||||||
|
return line.del_period.description or ''
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@property
|
||||||
|
def report_shipment_periods(self):
|
||||||
|
periods = []
|
||||||
|
for line in self._get_report_lines():
|
||||||
|
period = line.del_period.description if line.del_period else ''
|
||||||
|
if period and period not in periods:
|
||||||
|
periods.append(period)
|
||||||
|
if periods:
|
||||||
|
return '\n'.join(periods)
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def report_payment_date(self):
|
def report_payment_date(self):
|
||||||
if self.lines:
|
line = self._get_report_first_line()
|
||||||
if self.lc_date:
|
if line:
|
||||||
return format_date_en(self.lc_date)
|
if self.lc_date:
|
||||||
Date = Pool().get('ir.date')
|
return format_date_en(self.lc_date)
|
||||||
payment_date = self.lines[0].sale.payment_term.lines[0].get_date(Date.today(),self.lines[0])
|
Date = Pool().get('ir.date')
|
||||||
if payment_date:
|
payment_date = line.sale.payment_term.lines[0].get_date(Date.today(), line)
|
||||||
payment_date = format_date_en(payment_date)
|
if payment_date:
|
||||||
return payment_date
|
payment_date = format_date_en(payment_date)
|
||||||
|
return payment_date
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def report_shipment(self):
|
def report_shipment(self):
|
||||||
|
|||||||
@@ -154,5 +154,46 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
|||||||
sale.crop.name = 'Main Crop'
|
sale.crop.name = 'Main Crop'
|
||||||
self.assertEqual(sale.report_crop_name, 'Main Crop')
|
self.assertEqual(sale.report_crop_name, 'Main Crop')
|
||||||
|
|
||||||
|
def test_sale_report_multi_line_helpers_aggregate_all_lines(self):
|
||||||
|
'sale report helpers aggregate quantity, price lines and shipment periods'
|
||||||
|
Sale = Pool().get('sale.sale')
|
||||||
|
|
||||||
|
def make_line(quantity, period, linked_price):
|
||||||
|
line = Mock()
|
||||||
|
line.type = 'line'
|
||||||
|
line.quantity = quantity
|
||||||
|
line.note = ''
|
||||||
|
line.price_type = 'priced'
|
||||||
|
line.unit_price = Decimal('0')
|
||||||
|
line.linked_price = Decimal(linked_price)
|
||||||
|
line.linked_currency = Mock(rec_name='USC')
|
||||||
|
line.linked_unit = Mock(rec_name='POUND')
|
||||||
|
line.unit = Mock(rec_name='MT')
|
||||||
|
line.del_period = Mock(description=period)
|
||||||
|
line.get_pricing_text = f'ON ICE Cotton #2 {period}'
|
||||||
|
line.lots = []
|
||||||
|
return line
|
||||||
|
|
||||||
|
sale = Sale()
|
||||||
|
sale.currency = Mock(rec_name='USD')
|
||||||
|
sale.lines = [
|
||||||
|
make_line('1000', 'MARCH 2026', '72.5000'),
|
||||||
|
make_line('1000', 'MAY 2026', '70.2500'),
|
||||||
|
]
|
||||||
|
|
||||||
|
self.assertEqual(sale.report_total_quantity, '2000.0')
|
||||||
|
self.assertEqual(sale.report_quantity_unit_upper, 'MT')
|
||||||
|
self.assertEqual(sale.report_qt, 'TWO THOUSAND METRIC TONS')
|
||||||
|
self.assertEqual(sale.report_nb_bale, '')
|
||||||
|
self.assertEqual(
|
||||||
|
sale.report_shipment_periods.splitlines(),
|
||||||
|
['MARCH 2026', 'MAY 2026'])
|
||||||
|
self.assertEqual(
|
||||||
|
sale.report_price_lines.splitlines(),
|
||||||
|
[
|
||||||
|
'USC 72.5000 PER POUND (SEVENTY TWO USC AND FIFTY CENTS) ON ICE Cotton #2 MARCH 2026',
|
||||||
|
'USC 70.2500 PER POUND (SEVENTY USC AND TWENTY FIVE CENTS) ON ICE Cotton #2 MAY 2026',
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
del ModuleTestCase
|
del ModuleTestCase
|
||||||
|
|||||||
@@ -4091,7 +4091,7 @@
|
|||||||
<text:p text:style-name="P42" />
|
<text:p text:style-name="P42" />
|
||||||
</table:table-cell>
|
</table:table-cell>
|
||||||
<table:table-cell table:style-name="Table4.A1" office:value-type="string">
|
<table:table-cell table:style-name="Table4.A1" office:value-type="string">
|
||||||
<text:p text:style-name="P31">ABOUT <text:placeholder text:placeholder-type="text"><sum(line.quantity for line in sale.lines)></text:placeholder><text:s /><text:placeholder text:placeholder-type="text"><sale.lines[0].unit.rec_name.upper() if sale.lines and sale.lines[0].unit else ''></text:placeholder><text:s /><text:span text:style-name="T23">(</text:span><text:span text:style-name="T23"><text:placeholder text:placeholder-type="text"><sale.report_qt></text:placeholder></text:span><text:span text:style-name="T23">) </text:span></text:p>
|
<text:p text:style-name="P31">ABOUT <text:placeholder text:placeholder-type="text"><sale.report_total_quantity></text:placeholder><text:s /><text:placeholder text:placeholder-type="text"><sale.report_quantity_unit_upper></text:placeholder><text:s /><text:span text:style-name="T23">(</text:span><text:span text:style-name="T23"><text:placeholder text:placeholder-type="text"><sale.report_qt></text:placeholder></text:span><text:span text:style-name="T23">) </text:span></text:p>
|
||||||
<text:p text:style-name="P39">
|
<text:p text:style-name="P39">
|
||||||
<text:placeholder text:placeholder-type="text"><sale.report_nb_bale></text:placeholder>
|
<text:placeholder text:placeholder-type="text"><sale.report_nb_bale></text:placeholder>
|
||||||
</text:p>
|
</text:p>
|
||||||
@@ -4110,27 +4110,13 @@
|
|||||||
</table:table-cell>
|
</table:table-cell>
|
||||||
<table:table-cell table:style-name="Table5.A1" office:value-type="string">
|
<table:table-cell table:style-name="Table5.A1" office:value-type="string">
|
||||||
<text:p text:style-name="P56">
|
<text:p text:style-name="P56">
|
||||||
<text:placeholder text:placeholder-type="text"><sale.lines[0].linked_currency.rec_name.upper() if sale.lines[0].linked_currency else sale.currency.rec_name.upper()></text:placeholder>
|
<text:placeholder text:placeholder-type="text"><for each="line in sale.report_price_lines.splitlines()"></text:placeholder>
|
||||||
<text:s />
|
</text:p>
|
||||||
<text:placeholder text:placeholder-type="text"><sale.lines[0].linked_price if sale.lines[0].linked_price else sale.lines[0].unit_price></text:placeholder>
|
<text:p text:style-name="P56">
|
||||||
<text:span text:style-name="T23">
|
<text:placeholder text:placeholder-type="text"><line></text:placeholder>
|
||||||
<text:s />
|
</text:p>
|
||||||
</text:span>
|
<text:p text:style-name="P56">
|
||||||
<text:span text:style-name="T26">PER </text:span>
|
<text:placeholder text:placeholder-type="text"></for></text:placeholder>
|
||||||
<text:span text:style-name="T26">
|
|
||||||
<text:placeholder text:placeholder-type="text"><sale.lines[0].linked_unit.rec_name.upper() if sale.lines[0].linked_unit else sale.lines[0].unit.rec_name.upper()></text:placeholder>
|
|
||||||
</text:span>
|
|
||||||
<text:span text:style-name="T26">
|
|
||||||
<text:s />
|
|
||||||
</text:span>
|
|
||||||
<text:span text:style-name="T23">(</text:span>
|
|
||||||
<text:span text:style-name="T26">
|
|
||||||
<text:placeholder text:placeholder-type="text"><sale.report_price></text:placeholder>
|
|
||||||
</text:span>
|
|
||||||
<text:span text:style-name="T23">) </text:span>
|
|
||||||
<text:span text:style-name="T23">
|
|
||||||
<text:placeholder text:placeholder-type="text"><sale.lines[0].get_pricing_text></text:placeholder>
|
|
||||||
</text:span>
|
|
||||||
</text:p>
|
</text:p>
|
||||||
<text:p text:style-name="P37" />
|
<text:p text:style-name="P37" />
|
||||||
</table:table-cell>
|
</table:table-cell>
|
||||||
@@ -4199,12 +4185,18 @@
|
|||||||
</text:p>
|
</text:p>
|
||||||
</table:table-cell>
|
</table:table-cell>
|
||||||
<table:table-cell table:style-name="Table6.A1" office:value-type="string">
|
<table:table-cell table:style-name="Table6.A1" office:value-type="string">
|
||||||
|
<text:p text:style-name="P36">
|
||||||
|
<text:placeholder text:placeholder-type="text"><for each="line in sale.report_shipment_periods.splitlines()"></text:placeholder>
|
||||||
|
</text:p>
|
||||||
<text:p text:style-name="P36">
|
<text:p text:style-name="P36">
|
||||||
<text:s />
|
<text:s />
|
||||||
<text:span text:style-name="T24">
|
<text:span text:style-name="T24">
|
||||||
<text:placeholder text:placeholder-type="text"><sale.report_delivery_period_description></text:placeholder>
|
<text:placeholder text:placeholder-type="text"><line></text:placeholder>
|
||||||
</text:span>
|
</text:span>
|
||||||
</text:p>
|
</text:p>
|
||||||
|
<text:p text:style-name="P36">
|
||||||
|
<text:placeholder text:placeholder-type="text"></for></text:placeholder>
|
||||||
|
</text:p>
|
||||||
<text:p text:style-name="P34" />
|
<text:p text:style-name="P34" />
|
||||||
</table:table-cell>
|
</table:table-cell>
|
||||||
</table:table-row>
|
</table:table-row>
|
||||||
|
|||||||
Reference in New Issue
Block a user