TIP: You can type at any time to perform a new search.
Romania - Retail Price Change (Proces Verbal Schimbare Pret)
l10n_ro_stock_account_retail_price_change · OCA/l10n-romania
- Repository
- OCA/l10n-romania · module folder · Try on Runboat
- Module version
- 1.0.0
- Category
- Localization
- Folder size
- 0.26 MB
- License
- AGPL-3
- Application
- No
- Auto-installable
- No
- Website
- https://github.com/OCA/l10n-romania
- Last tracking update
- 2026-09-18 11:33:44
- Authors
- Odoo Community Association (OCA), NextERP Romania, Dakai Soft SRL
- Maintainers
- Odoo Community Association (OCA), NextERP Romania, Dakai Soft SRL
- Committers
- Mihai Fekete, OCA-git-bot, oca-ci
- Odoo dependencies
- Python dependencies
- None
- System dependencies
- None
- Required by
- None
- Description
# Romania - Retail Price Change (Proces Verbal de Schimbare Pret) Adds the price change document to the retail merchandise accounting of `l10n_ro_stock_account_retail`. `l10n.ro.retail.price.change` is a persistent document numbered `PVSP/YYYY/00000` out of a sequence of its own company. It captures the warehouse, the date, the products on hand and the old versus new shelf price (PVA, VAT included) per line, with the markup (378) and deferred VAT (4428) split. The old side is what the stock carries — cost, markup and deferred VAT per unit, read from the markup ledger — and it is read again when the document is posted, so the delta always measures the gap that exists at the moment the entry is made. A posted document is final: it is revoked by posting another one, never reset, cancelled or deleted. There are three flows: 1. **Manual** - create a draft, load the products on hand, edit the new prices, then post. Posting writes the new prices on the warehouse retail pricelist, books the revaluation and records it in the markup ledger, so the next sale releases the new markup and not the old one. 2. **Automatic** - a draft document is raised for each affected retail warehouse whenever a shelf price moves, and the user reviews it and posts it. What decided the price does not matter: a fixed rule, a rule over a category or the whole shop, any term of a formula, a change on another pricelist the shop derives from, or the product's own sale price. The price before and the price after are compared per product and per shop, so a rule that names a whole range raises a document holding the labels that actually moved. A shop has at most one open automatic document, topped up as prices keep moving, so it always quotes the price that is on the label. Posting writes a fixed rule back on the pricelist only where the pricelist does not already answer with the price decided, which is what keeps a shop priced by formula priced by formula. 3. **Reconciled** - a daily cron, *Retail: Reconcile Shelf Prices*, compares what the markup ledger says each unit on the shelf carries with what the pricelist says the label reads, and raises a draft wherever the two have parted company. That catches the prices which move with nobody writing anything: the day a dated promotion opens, a shelf price computed over a cost that a reception has moved, a change of VAT rate. Stock the ledger does not yet account for is left to the opening balance wizard. ## Report The document prints as *Proces-verbal privind modificarea pretului de vanzare cu amanuntul*, listing quantity, old and new price, old and new value and the difference per product, with the markup and VAT split shown separately. ## Price history Every posted document is a dated record of the shelf price of the products it covers. The *Price History* button on a product shows the lines that concern it, oldest first, so the sequence of shelf prices and the document that decided each of them are visible in one place.
Code Analysis ⓘ
Views touched (6)
| XML ID | Name | Model | Type | Status |
|---|---|---|---|---|
report_retail_price_change |
report_retail_price_change | ir.ui.view | qweb | New |
view_product_template_retail_price_change_form |
product.template.form.l10n.ro.retail.price.change | product.template | form | Inherits product.product_template_form_view |
view_retail_price_change_form |
l10n.ro.retail.price.change.form | l10n.ro.retail.price.change | form | New |
view_retail_price_change_line_history_list |
l10n.ro.retail.price.change.line.history.list | l10n.ro.retail.price.change.line | list | New |
view_retail_price_change_list |
l10n.ro.retail.price.change.list | l10n.ro.retail.price.change | list | New |
view_retail_price_change_search |
l10n.ro.retail.price.change.search | l10n.ro.retail.price.change | search | New |
HTTP endpoints (0)
No HTTP endpoints found for this module.
Models touched (7)
New fields (1)
-
price_change_idMany2one → l10n.ro.retail.price.changeindex='btree_not_null'ondelete='set null'string='Price Change' args: 'l10n.ro.retail.price.change'
No public methods.
New fields (12)
-
account_move_idMany2one → account.movecopy=Falsereadonly=True args: 'account.move' -
auto_createdBooleancopy=Falsehelp='True when this document was generated automatically from a pricelist change.'readonly=True -
company_idMany2one → res.companydefault=<expr>readonly=Truerequired=True args: 'res.company' -
dateDatedefault=fields.Date.context_todayrequired=Truetracking=True -
journal_idMany2one → account.journalcompute='_compute_journal_id'domain="[('company_id', '=', company_id)]"readonly=Falsestore=True args: 'account.journal' -
line_idsOne2many → l10n.ro.retail.price.change.linecopy=Truestring='Lines' args: 'l10n.ro.retail.price.change.line', 'document_id' -
markup_line_idsOne2many → l10n.ro.retail.markup.linereadonly=Truestring='Markup Ledger' args: 'l10n.ro.retail.markup.line', 'price_change_id' -
nameCharcopy=Falsedefault='/'index=Truereadonly=Truetracking=True -
notesHtml -
pricelist_idMany2one → product.pricelistcompute='_compute_pricelist_id'readonly=Falsestore=True args: 'product.pricelist' -
stateSelectiondefault='draft'required=Truetracking=True args: [('draft', 'Draft'), ('done', 'Done'), ('cancel', 'Cancelled')] -
warehouse_idMany2one → stock.warehousedomain="[('l10n_ro_retail', '=', True), ('company_id', '=', company_id)]"required=Truetracking=True args: 'stock.warehouse'
-
action_cancel(self)Drop a document that was never posted. Only from draft, and there is no way back from done. A posted Proces Verbal wrote the shelf prices, posted an entry and moved what the stock carries; undoing it in place would leave the three out of step with each other and the printed document out of step with the books. A price decision that turned out wrong is revoked the way it was made, by posting another one. -
action_load_products(self) -
action_post(self) -
action_view_move(self) -
create(self, vals_list)@api.model_create_multiNumber each document out of the sequence of its own company. ``next_by_code`` reads ``self.env.company``, which is not necessarily the company of the document being created: the pricelist hook raises one document per retail warehouse, in sudo, and a warehouse can belong to another company of the group. With a sequence per company that would hand a document the series of a different firm.
New fields (18)
-
company_idMany2onerelated='document_id.company_id'store=True -
cost_unitMonetarycompute='_compute_carried'help='Cost the stock on hand carries, from the markup ledger.'store=Truestring='Cost / Unit' -
currency_idMany2onereadonly=Truerelated='company_id.currency_id' -
document_dateDateindex=Truerelated='document_id.date'store=Truestring='Date' -
document_idMany2one → l10n.ro.retail.price.changeindex=Trueondelete='cascade'required=True args: 'l10n.ro.retail.price.change' -
location_idMany2one → stock.locationrequired=True args: 'stock.location' -
markup_diff_totalMonetarycompute='_compute_splits'store=Truestring='Markup Delta' -
new_markup_unitMonetarycompute='_compute_splits'store=Truestring='New Markup / Unit' -
new_price_with_vatMonetaryhelp='New retail price including VAT.'string='New PVA' -
new_vat_unitMonetarycompute='_compute_splits'store=Truestring='New VAT / Unit' -
old_markup_unitMonetarycompute='_compute_carried'help='Markup the stock carries on 378 per unit, as recorded.'store=Truestring='Old Markup / Unit' -
old_price_with_vatMonetarycompute='_compute_old_price'help='What the stock on the shelf carries per unit, VAT included - the cost plus the markup and deferred VAT recorded against it. This is what 371 holds, which is not always what the pricelist says.'store=Truestring='Old PVA' -
old_vat_unitMonetarycompute='_compute_carried'help='Deferred VAT the stock carries on 4428 per unit, as recorded.'store=Truestring='Old VAT / Unit' -
product_idMany2one → product.productrequired=True args: 'product.product' -
quantityFloatdigits='Product Unit of Measure'readonly=True -
stateSelectionrelated='document_id.state'store=False -
vat_diff_totalMonetarycompute='_compute_splits'store=Truestring='VAT Delta' -
warehouse_idMany2onerelated='document_id.warehouse_id'store=Truestring='Warehouse'
No public methods.
New fields (0)
No new fields.
Public methods (3)-
create(self, vals_list)@api.model_create_multiA new rule has no price from before to be compared against. So the comparison is made against what the goods on the shelf carry - account 371 against the label, the invariant itself. Comparing against nothing instead, as though every price had moved up from zero, put every article the rule reaches on a document: harmless once posted, because a line whose two sides agree books no entry, but a rule covering a whole category handed the shop a draft listing its entire assortment to read through. -
unlink(self)Deleting a rule moves the shelf price too. The label then shows whatever answers next - the rule underneath, or the sale price - while 371 still carries the price the deleted rule set. That is the same divergence a price edit causes, and it deserves the same Proces Verbal. The prices after have to be read once the rule is gone, so the targets are carried over from before the delete. -
write(self, vals)
New fields (0)
No new fields.
Public methods (0)No public methods.
New fields (1)
-
l10n_ro_retail_price_change_countIntegercompute='_compute_l10n_ro_retail_price_change_count'string='Retail Price Changes'
-
action_l10n_ro_retail_price_history(self)Every shelf price this product has had, and the document that decided each of them. -
write(self, vals)A shop priced off the sale price re-prices its shelves here. ``base='list_price'`` is the default of a formula rule and the most common way a shop is set up: the shelf price is the sale price, or the sale price less a discount. For that shop the repricing action is editing the product, and nothing at all is written on the pricelist - so watching only ``product.pricelist.item`` saw none of it, and 371 stayed on the old price with no document raised. The cost is the other base a formula can have, and it is deliberately not watched here. ``standard_price`` is written by the valuation on every reception under average cost, which is the hot path of every goods movement in the database, and hanging a price snapshot off it would make every receipt pay for a check that almost never finds anything. A shelf price that follows the cost is caught by the nightly reconciliation instead, which is where the other prices that move without anyone writing them are caught too.
New fields (0)
No new fields.
Public methods (1)-
create(self, vals_list)@api.model_create_multi