6.2 KiB
BR-PT-004 - Market Price Import
Intent
Import dated market prices from an .xlsx Excel file into price.price_value, using price.price as the market price index.
Scope
- Wizard:
purchase_trade.import_prices - Input model:
purchase_trade.import_prices.start - Result model:
purchase_trade.import_prices.result - Target models:
price.priceprice.price_value
- Menu entry: under
price.menu_price
Inputs
The wizard reads only the first worksheet of an .xlsx file.
The first row is treated as the header row. Header names are normalized by lowercasing and removing non-alphanumeric characters, so labels such as price_index, price index, and Price Index map to the same field.
Required columns:
price_indexprice_datehigh_pricelow_priceopen_priceprice_value
The wizard options are:
Create price index if missingOverwrite existing price
Date and Numeric Parsing
Accepted price_date values:
- Excel serial date numbers
YYYY-MM-DDDD/MM/YYYYMM/DD/YYYY
Numeric price fields accept decimal commas or decimal points. Empty numeric cells are imported as empty values. Invalid numeric values are reported as row errors.
Expected Behavior
For each non-empty data row, starting from Excel row 2:
- Trim and validate
price_index. - Parse
price_date. - Search
price.priceby exactprice_index. - If the price index is missing:
- create it when
Create price index if missingis checked - otherwise skip the row with
price_index missing
- create it when
- Search
price.price_valueby(price, price_date). - If an existing price value is found:
- update it when
Overwrite existing priceis checked - otherwise skip the row with
price_date already exists
- update it when
- If no existing price value is found, create a new
price.price_value.
Created Price Index Defaults
When the wizard creates a missing price.price, it sets:
price_index = imported price_indexprice_desc = imported price_indexprice_curve_type = future
It also tries to default these references when matching records exist:
price_type:price.fixtypewherename = Market priceprice_currency:currency.currencywherecode = USDprice_calendar:price.calendarwherename = Argus EUprice_unit:product.uomwherename = Mt
If the price_index contains a YYYY-MM style period, the wizard derives a product.month:
- pattern accepted in the name:
YYYY-MM,YYYY/MM,YYYY_MM,YYYY.MM, orYYYY MM - month name format:
MONYY, for exampleJUL26 - if no matching
product.monthexists, it is created withis_cotation = True
Result Reporting
The result screen always shows counts and detail sections for:
- created price indexes
- imported prices
- updated existing prices
- skipped records
- errors
Row-level errors do not stop the whole import; the wizard records the error and continues with the next row.
Edge Cases
- Missing
price_index: skipped. - Missing
price_date: skipped. - Invalid
.xlsxfile: blockingUserError. - Missing required columns: blocking
UserError. - Invalid date: row error.
- Invalid numeric value: row error.
- Existing
(price, price_date)without overwrite option: skipped. - Existing
(price, price_date)with overwrite option: updated. - Empty rows are ignored.
Impacted Files
Direct purchase_trade files:
modules/purchase_trade/pricing.pymodules/purchase_trade/pricing.xmlmodules/purchase_trade/view/import_prices_start_form.xmlmodules/purchase_trade/view/import_prices_result_form.xmlmodules/purchase_trade/__init__.pymodules/purchase_trade/tryton.cfgmodules/purchase_trade/tests/test_module.py
External model dependencies:
modules/price/price.pymodules/price/price_value.pymodules/price/view/price_value_form.xml
Tests
Existing focused tests cover:
- missing price index skipped when creation is disabled
- missing price index created when creation is enabled
- default fields on newly created price indexes
- period reuse/creation from
price_index - existing
price_dateskipped when overwrite is disabled - existing
price_dateupdated when overwrite is enabled - invalid row values collected as errors
- result screen formatting
Recommended additional tests:
.xlsxheader normalization- missing required columns
- Excel serial date parsing
- empty row ignored
- invalid workbook raises
UserError
Open Questions
-
Q: Should
(price, price_date)be enforced unique at model/database level? -
A: Enforce uniqueness at model level for now. Do not add a database constraint yet.
-
Q: Should created price index defaults remain hardcoded to
Market price,USD,Argus EU, andMt? -
A: Yes. Keep these defaults hardcoded for this import.
-
Q: Should ambiguous slash dates prefer
DD/MM/YYYYoverMM/DD/YYYY, as currently implemented? -
A: Prefer the user's/default locale date format when possible. Fall back to the current order only if no locale preference is available.
-
Comment: current code tries
DD/MM/YYYYbeforeMM/DD/YYYYand does not inspect locale. Implementing this answer requires a code change. -
Q: Should missing
price_valuebe allowed, or should it skip/error while high/low/open remain optional? -
A: Missing
price_valueis not allowed. Report the row as an error.high_price,low_price, andopen_priceremain optional. -
Comment: current code allows empty
price_valueand imports it as an empty value. Implementing this answer requires a code change. -
Q: Should duplicate rows for the same
(price_index, price_date)inside the same Excel file be treated as an error, skipped after the first row, or resolved by the overwrite option? -
A: Report duplicate rows as row errors and do not import or update the duplicate row.
-
Q: When
Create price index if missingis enabled, should missing default reference records (Market price,USD,Argus EU,Mt) block index creation or remain optional as currently implemented? -
A: Remain optional. Create the price index with the reference records that can be found.
-
Q: Should the import result distinguish business validation errors from technical parsing errors?
-
A: Yes. Distinguish business validation errors from file, parsing, and technical errors in the import result.