Import Prices (All Sources)
This commit is contained in:
@@ -2,9 +2,11 @@
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
import datetime
|
||||
import zipfile
|
||||
from pathlib import Path
|
||||
from contextlib import nullcontext
|
||||
from decimal import Decimal
|
||||
from io import BytesIO
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import ANY, Mock, call, patch
|
||||
from xml.etree import ElementTree
|
||||
@@ -5190,6 +5192,57 @@ class PurchaseTradeTestCase(ModuleTestCase):
|
||||
self.assertEqual(result[0]['mid_price'], '75.25')
|
||||
self.assertEqual(result[0]['high_price'], '75.25')
|
||||
|
||||
def test_import_historical_prices_computes_mid_from_low_high(self):
|
||||
'historical import computes mid price from low and high prices'
|
||||
ImportPrices = Pool().get('purchase_trade.import_prices')
|
||||
ns = {'s': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'}
|
||||
sheet = ElementTree.fromstring('''
|
||||
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<sheetData>
|
||||
<row r="1">
|
||||
<c r="A1" t="inlineStr"><is><t>Price Index</t></is></c>
|
||||
<c r="B1" t="inlineStr"><is><t>Price Date</t></is></c>
|
||||
<c r="C1" t="inlineStr"><is><t>High Price</t></is></c>
|
||||
<c r="D1" t="inlineStr"><is><t>Low Price</t></is></c>
|
||||
<c r="E1" t="inlineStr"><is><t>Open Price</t></is></c>
|
||||
<c r="F1" t="inlineStr"><is><t>Price Value</t></is></c>
|
||||
</row>
|
||||
<row r="2">
|
||||
<c r="A2" t="inlineStr"><is><t>ARGUS-CFR Brasil</t></is></c>
|
||||
<c r="B2"><v>46191</v></c>
|
||||
<c r="C2"><v>482</v></c>
|
||||
<c r="D2"><v>460</v></c>
|
||||
<c r="E2"><v>470</v></c>
|
||||
<c r="F2"><v>470</v></c>
|
||||
</row>
|
||||
</sheetData>
|
||||
</worksheet>
|
||||
''')
|
||||
rows = sheet.findall('.//s:sheetData/s:row', ns)
|
||||
|
||||
result = ImportPrices._read_historical_price_rows(rows, [], ns)
|
||||
values = ImportPrices._price_value_values(
|
||||
Mock(id=1), result[0], datetime.date(2026, 6, 18))
|
||||
|
||||
self.assertNotIn('mid_price', result[0])
|
||||
self.assertEqual(values['mid_price'], 471)
|
||||
|
||||
def test_import_forward_price_values_compute_mid_from_low_high(self):
|
||||
'forward import value builder computes mid price from low and high'
|
||||
ImportPrices = Pool().get('purchase_trade.import_prices')
|
||||
|
||||
values = ImportPrices._price_value_values(
|
||||
Mock(id=1), {
|
||||
'high_price': '482',
|
||||
'low_price': '460',
|
||||
'mid_price': '0',
|
||||
'open_price': '470',
|
||||
'price_value': '470',
|
||||
},
|
||||
datetime.date(2026, 6, 18))
|
||||
|
||||
self.assertEqual(values['mid_price'], 471)
|
||||
|
||||
@with_transaction()
|
||||
def test_import_historical_all_sources_uses_mapping_table(self):
|
||||
'all sources import maps source columns to standard price values'
|
||||
@@ -5211,7 +5264,7 @@ description</t></is></c>
|
||||
<row r="3">
|
||||
<c r="A3"><v>46191</v></c>
|
||||
<c r="B3"><v>470</v></c>
|
||||
<c r="C3"><v>480</v></c>
|
||||
<c r="C3"><v>482</v></c>
|
||||
<c r="D3"><v>460</v></c>
|
||||
</row>
|
||||
</sheetData>
|
||||
@@ -5261,10 +5314,75 @@ description</t></is></c>
|
||||
self.assertEqual(result[0]['price_date'], '46191')
|
||||
self.assertEqual(result[0]['mid_price'], '470')
|
||||
self.assertEqual(result[0]['price_value'], '470')
|
||||
self.assertEqual(result[0]['high_price'], '480')
|
||||
self.assertEqual(result[0]['open_price'], '470')
|
||||
self.assertEqual(result[0]['high_price'], '482')
|
||||
self.assertEqual(result[0]['low_price'], '460')
|
||||
self.assertEqual(result[0]['_source'], 'ARGUS')
|
||||
self.assertEqual(result[0]['_price_desc'], 'Brazil CFR')
|
||||
values = ImportPrices._price_value_values(
|
||||
Mock(id=1), result[0], datetime.date(2026, 6, 18))
|
||||
self.assertEqual(values['mid_price'], 470)
|
||||
|
||||
def test_import_xlsx_uses_selected_parser(self):
|
||||
'price import selects parser from requested file structure'
|
||||
ImportPrices = Pool().get('purchase_trade.import_prices')
|
||||
workbook = BytesIO()
|
||||
with zipfile.ZipFile(workbook, 'w') as archive:
|
||||
archive.writestr('xl/workbook.xml', '''
|
||||
<workbook
|
||||
xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
|
||||
xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
|
||||
<sheets>
|
||||
<sheet name="Prices" sheetId="1" r:id="rId1"/>
|
||||
</sheets>
|
||||
</workbook>
|
||||
''')
|
||||
archive.writestr('xl/_rels/workbook.xml.rels', '''
|
||||
<Relationships
|
||||
xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
||||
<Relationship Id="rId1" Target="worksheets/sheet1.xml"/>
|
||||
</Relationships>
|
||||
''')
|
||||
archive.writestr('xl/worksheets/sheet1.xml', '''
|
||||
<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
|
||||
<sheetData>
|
||||
<row r="1">
|
||||
<c r="A1" t="inlineStr"><is><t>Price Index</t></is></c>
|
||||
<c r="B1" t="inlineStr"><is><t>Price Date</t></is></c>
|
||||
</row>
|
||||
<row r="2">
|
||||
<c r="A2" t="inlineStr"><is><t>ARGUS-CFR Brasil</t></is></c>
|
||||
<c r="B2"><v>46191</v></c>
|
||||
</row>
|
||||
</sheetData>
|
||||
</worksheet>
|
||||
''')
|
||||
data = workbook.getvalue()
|
||||
|
||||
with patch.object(
|
||||
ImportPrices, '_read_historical_price_rows',
|
||||
return_value=['historical']) as historical, \
|
||||
patch.object(
|
||||
ImportPrices, '_read_historical_all_sources_price_rows',
|
||||
return_value=['all_sources']) as all_sources, \
|
||||
patch.object(
|
||||
ImportPrices, '_read_forward_price_rows',
|
||||
return_value=['forward']) as forward:
|
||||
self.assertEqual(
|
||||
ImportPrices._read_xlsx(
|
||||
data, file_structure='historical'),
|
||||
['historical'])
|
||||
self.assertEqual(
|
||||
ImportPrices._read_xlsx(
|
||||
data, file_structure='historical_all_sources'),
|
||||
['all_sources'])
|
||||
self.assertEqual(
|
||||
ImportPrices._read_xlsx(data, file_structure='forward'),
|
||||
['forward'])
|
||||
|
||||
self.assertEqual(historical.call_count, 1)
|
||||
self.assertEqual(all_sources.call_count, 1)
|
||||
self.assertEqual(forward.call_count, 1)
|
||||
|
||||
def test_import_historical_all_sources_requires_exact_tab_match(self):
|
||||
'all sources import ignores similarly named source sheets'
|
||||
@@ -5295,6 +5413,14 @@ description</t></is></c>
|
||||
self.assertEqual(values['price_desc'], 'Brazil CFR')
|
||||
self.assertEqual(values['price_area'], 8)
|
||||
|
||||
def test_import_price_date_accepts_dot_format(self):
|
||||
'price import accepts dd.mm.yyyy dates'
|
||||
ImportPrices = Pool().get('purchase_trade.import_prices')
|
||||
|
||||
result = ImportPrices._as_date('18.06.2026')
|
||||
|
||||
self.assertEqual(result, datetime.date(2026, 6, 18))
|
||||
|
||||
def test_pricing_component_matrix_returns_generic_line_price(self):
|
||||
'matrix pricing can use an unconditional matrix line as a component price'
|
||||
Component = Pool().get('pricing.component')
|
||||
|
||||
Reference in New Issue
Block a user