Accounting Scenario Framework
by Terrabit https://www.terrabit.ro , Dorin Hongu https://www.terrabit.ro| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Inventory (stock)
• Invoicing (account) • Discuss (mail) • Purchase (purchase) |
| Lines of code | 2399 |
| Technical Name |
deltatech_account_scenario |
| License | LGPL-3 |
| Website | https://www.terrabit.ro |
Accounting Scenario Framework
Framework for running and validating accounting scenarios via JSON
Overview
deltatech_account_scenario is an Odoo 19 module that provides a
JSON-driven framework for running and validating complete accounting
scenarios. It allows developers and accountants to define business
processes (invoices, payments, journal entries, fixed assets, stock
receipts, deliveries, etc.) as JSON scenarios, execute them against a
live Odoo database, and automatically validate the resulting accounting
entries and stock valuations.
The module supports two modes of operation:
- Test mode — executes a scenario and validates that the generated account moves and stock values match the expected entries defined in the JSON.
- Demo mode — executes a scenario to generate demo/sample data without strict accounting validation.
Features
JSON-Driven Scenarios
- ✓Define complete business processes as structured JSON, including steps (actions) and expected accounting/stock entries.
- ✓Steps are divided into two categories:
- Master data steps — create or resolve reference data (accounts, partners, product categories, products).
- Transactional steps — execute business operations (purchase orders, stock receipts, vendor bills, sale orders, invoices, stock pickings, journal entries, payments).
- ✓Each step can include a
_commentfield; if present, its value is used as the log message instead of the auto-generated one.
Accounting & Stock Validation
- ✓After executing all steps, the runner compares the generated
account.move.lineentries against theexpected_account_movessection of the JSON. - ✓Validates account codes, debit/credit amounts, and analytic accounts.
- ✓Validates stock quantities and values per product via the
checkssection in each step. - ✓Reports mismatches clearly in the run log.
UI Integration
- Scenario list— view and manage JSON scenarios; import JSON files via the Import Scenarios button (always visible, no selection required).
- Scenario form— view, edit, and export a scenario as JSON via the Export JSON button.
- Run history— each execution is recorded as a
account.test.runrecord with full execution log and validation result. - Log navigation— clicking a log line with a document reference opens the related document (invoice, picking, payment, etc.) directly.
- Buttons— “Set Ready”, “Execute Scenario”, “Re-run Scenario”, “View Runs” available from the scenario form.
- ✓Menu: Accounting → Account Scenarios → Test Scenarios and Test Runs (accessible via the Accounting main menu).
Built-in Scenario Library
- ✓Ships with base data (
00_base_data.json) defining shared product categories, partners, and products used across all scenarios. - ✓Includes demo scenarios for purchase/sale flows, inventory transfers, stock receipts with invoices, and stock pickings.
- ✓Includes 140 Romanian stock accounting test scenarios under
data/scenarios/ro_stock/:- 70 FIFO scenarios (
ro_stock_fifo_case_XXXX.json) — covering FIFO cost method edge cases per Romanian accounting regulations. - 70 Average cost scenarios (
ro_stock_avg_case_XXXX.json) — covering weighted average cost method edge cases.
- 70 FIFO scenarios (
Automated Tests
- Includes
TransactionCasetests undertests/test_stock_scenarios.pyandtests/common.pycovering:- Product category creation step
- Partner creation step
- Product creation step
- Invoice creation and posting step
- Full scenario execution
- Purchase and sale with accounting checks
- Error handling for unknown step types
Models
| Model | Description |
|---|---|
stock.test.scenario |
Stores the JSON scenario definition, mode, and state |
account.test.run |
Records each execution with log, result, and link to scenario |
stock.test.log |
Individual log lines for each step: step
number, type, state
(ok/error/info), message, and
document reference |
Dependencies
- ✓
account— accounting entries and journals - ✓
stock— stock pickings and locations - ✓
stock_account— stock valuation and accounting integration - ✓
purchase— purchase orders and vendor bills
Usage
JSON Scenario Format
{ "id": "my_scenario", "name": "Scenario Name", "mode": "test", "currency": "RON", "lines": [ ... ], "expected_account_moves": [ ... ] }
| Field | Type | Description |
|---|---|---|
id |
string | Unique identifier for the scenario |
name |
string | Human-readable name displayed in the UI |
mode |
string | "test" (validates
accounting) or "demo"
(no validation) |
currency |
string | ISO currency code (e.g.
"RON", "EUR") |
lines |
array | List of steps to execute in order |
expected_account_moves |
array | Expected accounting entries to validate after execution |
Master Data Steps
Master data steps create or resolve reference records (accounts,
partners, categories, products). They are idempotent — if the record
already exists it is reused, not duplicated. Typically placed in a
shared 00_base_data.json loaded before all scenarios.
create_account
Creates a chart of accounts entry.
{ "step": "create_account", "code": "371", "name": "Marfuri", "account_type": "asset_current" }
| Field | Required | Description |
|---|---|---|
code |
✅ | Account code (e.g. "371") |
name |
— | Account name (defaults to code if
omitted) |
account_type |
— | Odoo account type (e.g.
"asset_current",
"liability_payable"); default:
"asset_current" |
The account is stored in records with key account_<code>.
create_partner
Creates or updates a customer or supplier partner. If a partner with the
same vat or name already exists, it is updated with the values
from the step.
{ "step": "create_partner", "name": "Furnizor Test SRL", "ref": "supplier_1", "vat": "RO12345678", "country": "RO", "supplier_rank": 1, "customer_rank": 0 }
| Field | Required | Description |
|---|---|---|
name |
✅ | Partner name |
ref |
— | Internal reference — used to resolve
the partner in transactional steps
(e.g. "supplier_1") |
vat |
— | VAT / CIF number (e.g.
"RO12345678"); used as primary
lookup key if present |
country |
— | ISO country code (e.g. "RO",
"DE"); also accepted as
country_id |
supplier_rank |
— | Set to 1 for suppliers |
customer_rank |
— | Set to 1 for customers |
company_type |
— | "company" (default) or
"person" |
id |
— | Optional XML ID to register the partner for cross-scenario reference |
The partner is stored in records with key partner_<name_normalized>
and also partner_<ref> if ref is provided.
create_product_category
Creates or updates a product category with cost method, valuation properties, and accounting accounts. If a category with the same name already exists, it is updated.
{ "step": "create_product_category", "name": "Marfuri AVG", "property_cost_method": "average", "property_valuation": "real_time", "property_account_income_categ_id": "704", "property_account_expense_categ_id": "607", "property_stock_valuation_account_id": "371" }
| Field | Required | Description |
|---|---|---|
name |
✅ | Category name |
property_cost_method |
— | "standard",
"average", or
"fifo" |
property_valuation |
— | "real_time"
(perpetual/automatic) or
"periodic" (manual) |
property_account_income_categ_id |
— | Account code for income
(e.g. "704") |
property_account_expense_categ_id |
— | Account code for expense
(e.g. "607") |
property_stock_valuation_account_id |
— | Account code for stock
valuation (e.g. "371") |
parent_id |
— | Parent category name |
id |
— | Optional XML ID to register the category |
The category is stored in records with key categ_<name_normalized>
(spaces replaced by _).
create_product
Creates a storable or consumable product. If a product with the same
code already exists, it is updated.
{ "step": "create_product", "code": "PROD-AVG-001", "name": "Produs Medie Ponderata", "categ_key": "categ_Marfuri_AVG", "standard_price": 100.0, "list_price": 150.0, "type": "consu" }
| Field | Required | Description |
|---|---|---|
code |
✅ | Internal reference / default code — used to resolve the product in transactional steps |
name |
✅ | Product name |
categ_key |
— | Key of a previously created
category (e.g.
"categ_Marfuri_AVG") |
categ_name |
— | Category name to search
directly (alternative to
categ_key) |
standard_price |
— | Cost price |
list_price |
— | Sales price |
type |
— | "consu" (consumable) or
"service" (default:
"consu") |
is_storable |
— | Set to true to mark as
storable (requires
stock module) |
property_account_income_id |
— | Account code for income override |
property_account_expense_id |
— | Account code for expense override |
id |
— | Optional XML ID to register the product |
Note: In Odoo 19,"storable"products require thestockmodule. For maximum compatibility in reporting modules, prefer"type": "consu".
The product is stored in records with key product_<code>.
Deltatech Valuation Setup Steps
These steps configure the deltatech account determination engine (valuation classes, areas, modifiers, and determination rules).
create_valuation_class
Creates a product valuation class (used to group products for account determination).
{ "step": "create_valuation_class", "code": "MARFA", "name": "Marfuri" }
| Field | Required | Description |
|---|---|---|
code |
✅ | Unique code for the valuation class |
name |
✅ | Display name |
Stored in records with key valuation_class_<code>.
create_valuation_area
Creates a valuation area (e.g. a warehouse or storage zone used in account determination).
{ "step": "create_valuation_area", "code": "WH01", "name": "Depozit Principal", "journal_code": "STJ" }
| Field | Required | Description |
|---|---|---|
code |
✅ | Unique code for the valuation area |
name |
✅ | Display name |
journal_code |
— | Journal code to assign as stock_journal_id |
Stored in records with key valuation_area_<code>.
create_account_modifier
Creates an account modifier (used to differentiate account determination rules by operation type).
{ "step": "create_account_modifier", "code": "RET", "name": "Retur" }
| Field | Required | Description |
|---|---|---|
code |
✅ | Unique code |
name |
✅ | Display name |
Stored in records with key account_modifier_<code>.
create_account_determination
Creates or updates a product.account.determination rule that maps a
transaction key + optional valuation class/area/modifier to
debit/credit/valuation accounts.
{ "step": "create_account_determination", "transaction_key": "stock_in", "valuation_class_key": "valuation_class_MARFA", "valuation_area_key": "valuation_area_WH01", "account_modifier_key": "account_modifier_RET", "acc_src": "401", "acc_dest": "371", "acc_valuation": "371" }
| Field | Required | Description |
|---|---|---|
transaction_key |
✅ | Transaction key (e.g.
"stock_in",
"stock_out") |
valuation_class_key |
— | Key of a previously created valuation class |
valuation_area_key |
— | Key of a previously created valuation area |
account_modifier_key |
— | Key of a previously created account modifier |
acc_src |
— | Source account code |
acc_dest |
— | Destination account code |
acc_valuation |
— | Valuation account code |
Stored in records with key determination_<transaction_key>.
set_company_valuation_area
Sets the valuation area on the current company.
{ "step": "set_company_valuation_area", "valuation_area_key": "valuation_area_WH01" }
| Field | Required | Description |
|---|---|---|
valuation_area_key |
— | Key of a previously created valuation area |
area_code |
— | Valuation area code to
search directly
(alternative to
valuation_area_key) |
set_picking_type_account_modifier
Sets the account_modifier_id on a stock.picking.type identified
by its operation code.
{ "step": "set_picking_type_account_modifier", "picking_type_code": "incoming", "account_modifier_key": "account_modifier_RET" }
| Field | Required | Description |
|---|---|---|
picking_type_code |
— | Operation code:
"incoming",
"outgoing",
"internal" (default:
"incoming") |
account_modifier_key |
— | Key of a previously created account modifier |
account_modifier_code |
— | Account modifier code to
search directly
(alternative to
account_modifier_key) |
set_product_valuation_class
Assigns a valuation class to a product.
{ "step": "set_product_valuation_class", "product_key": "product_PROD-AVG-001", "valuation_class_key": "valuation_class_MARFA" }
| Field | Required | Description |
|---|---|---|
product_key |
— | Key of a previously created product |
product_code |
— | Product default code to
search directly
(alternative to
product_key) |
valuation_class_key |
— | Key of a previously created valuation class |
valuation_class_code |
— | Valuation class code to
search directly
(alternative to
valuation_class_key) |
Transactional Steps
Transactional steps execute business operations against the database.
Products and partners are resolved by code/ref from previously
created master data or from existing records.
purchase
All-in-one step: creates and confirms a purchase order, receives all goods, and creates and posts the vendor bill.
{ "step": "purchase", "product": "PROD-AVG-001", "qty": 5.0, "price": 100.0, "partner": "supplier_1", "inv_qty": 5.0, "inv_price": 100.0 }
Multi-line format:
{ "step": "purchase", "products": [ {"product": "PROD-AVG-001", "qty": 5.0, "price": 100.0}, {"product": "MP-001", "qty": 10.0, "price": 50.0} ], "partner": "supplier_1" }
| Field | Required | Description |
|---|---|---|
product |
✅ (single) | Product code |
qty |
✅ (single) | Ordered and received quantity |
price |
✅ (single) | Unit price |
products |
✅ (multi) | List of {product, qty, price}
objects |
partner |
✅ | Partner ref or name |
inv_qty |
— | Invoice quantity override
(single-product mode); defaults to
qty |
inv_price |
— | Invoice unit price override
(single-product mode); defaults to
price |
Records stored: purchase_order_<idx>, receipt_<idx>,
vendor_bill_<idx>.
create_purchase_order
Creates and confirms a purchase order only (no receive, no invoice).
{ "step": "create_purchase_order", "product": "PROD-AVG-001", "qty": 5.0, "price": 100.0, "partner": "supplier_1", "currency": "RON", "notice": false }
Multi-line format:
{ "step": "create_purchase_order", "products": [ {"product": "PROD-AVG-001", "qty": 5.0, "price": 100.0}, {"product": "MP-001", "qty": 10.0, "price": 50.0} ], "partner": "supplier_1", "currency": "RON" }
| Field | Required | Description |
|---|---|---|
product |
✅ (single) | Product code to order |
qty |
✅ (single) | Ordered quantity |
price |
✅ (single) | Unit price |
products |
✅ (multi) | List of {product, qty, price}
objects |
partner |
✅ | Partner ref or name |
currency |
— | ISO currency code (e.g. "RON") |
date_order |
— | Order date in YYYY-MM-DD format;
defaults to current datetime if not
provided |
notice |
— | If true, propagates
l10n_ro_notice = True to the
subsequent receive_stock step
(Romanian NIR notice) |
The confirmed PO is stored as last_purchase_order and
purchase_order_<idx> in the execution context.
receive_stock
Receives goods on the last confirmed purchase order picking. Supports
both single-product and multi-product (products list) formats. The
picking is validated only after all moves are marked as received.
{ "step": "receive_stock", "product": "PROD-AVG-001", "qty": 5.0 }
Multiple products:
{ "step": "receive_stock", "products": [ {"product": "PROD-AVG-001", "qty": 5.0}, {"product": "MP-001", "qty": 10.0} ] }
| Field | Required | Description |
|---|---|---|
product |
— | Product code to receive (single-product mode); if omitted, all products are received |
qty |
— | Quantity to receive (single-product mode); defaults to ordered quantity |
products |
— | List of {product, qty} objects for
multi-product receive |
date |
— | Scheduled date for the picking in
YYYY-MM-DD format; defaults to current
datetime if not provided |
notice |
— | If true, sets
l10n_ro_notice = True on the picking
(Romanian NIR notice); overrides value
from create_purchase_order |
checks |
— | Optional stock validation after this step (see Checks section) |
Note:notice: truecan also be set oncreate_purchase_orderand will be propagated automatically to the subsequentreceive_stockstep.
Records stored: receipt_<idx>, last_receipt.
return_stock
Creates a stock return (reverse picking) for the last received stock picking or any picking by key.
{ "step": "return_stock", "qty": 3.0, "product": "PROD-AVG-001", "picking_key": "last_receipt" }
| Field | Required | Description |
|---|---|---|
qty |
— | Quantity to return (positive value); defaults to all received qty |
product |
— | Product code to return; if omitted, all products from the source picking are returned |
picking_key |
— | Key in records to use as source picking
(default: "last_receipt"); e.g.
"last_delivery" for sales returns |
date |
— | Scheduled date for the return picking
in YYYY-MM-DD format; defaults to
current datetime if not provided |
checks |
— | Optional stock validation after this step (see Checks section) |
The return picking is created with reversed source/destination locations
and origin_returned_move_id set correctly. Records stored:
return_<idx>, last_return.
create_vendor_bill
Creates and posts a vendor bill linked to the last purchase order.
Supports both single-product and multi-product (products list)
formats for overriding invoice line quantities/prices.
Credit note: Ifqtyis negative, a vendor credit note (in_refund) is created instead of a vendor bill.
{ "step": "create_vendor_bill", "qty": 5.0, "price": 100.0 }
Multiple products:
{ "step": "create_vendor_bill", "products": [ {"product": "PROD-AVG-001", "qty": 5.0, "price": 100.0}, {"product": "MP-001", "qty": 10.0, "price": 50.0} ] }
| Field | Required | Description |
|---|---|---|
qty |
— | Invoice quantity override for all lines (single-product mode); negative value creates a credit note |
price |
— | Invoice unit price override for all lines (single-product mode) |
invoice_date |
— | Invoice date in YYYY-MM-DD format;
defaults to today if not provided |
products |
— | List of {product, qty, price}
objects to override specific lines by
product |
Records stored: vendor_bill_<idx>, last_vendor_bill.
sale
All-in-one step: creates and confirms a sale order, delivers all goods, and creates and posts the customer invoice.
{ "step": "sale", "product": "PROD-AVG-001", "qty": 3.0, "price": 150.0, "partner": "customer_1" }
Multi-line format:
{ "step": "sale", "products": [ {"product": "PROD-AVG-001", "qty": 3.0, "price": 150.0}, {"product": "MP-001", "qty": 2.0, "price": 120.0} ], "partner": "customer_1" }
| Field | Required | Description |
|---|---|---|
product |
✅ (single) | Product code |
qty |
✅ (single) | Quantity to sell |
price |
✅ (single) | Unit sales price |
products |
✅ (multi) | List of {product, qty, price}
objects |
inv_qty |
— | Invoice quantity override (per line in
products, or global in single
mode) |
inv_price |
— | Invoice unit price override (per line
in products, or global in single
mode) |
partner |
✅ | Partner ref or name |
currency |
— | ISO currency code |
Records stored: sale_order_<idx>, last_sale_order,
delivery_<idx>, last_delivery, customer_invoice_<idx>,
last_customer_invoice.
inventory
Sets stock quantity via inventory adjustment (stock.quant).
{ "step": "inventory", "product": "PROD-AVG-001", "qty": 10.0, "location": "WH/Stock" }
| Field | Required | Description |
|---|---|---|
product |
✅ | Product code |
qty |
✅ | Target on-hand quantity |
location |
— | Location complete name (ilike match); defaults to the company’s main stock location |
date |
— | Inventory date in YYYY-MM-DD format;
defaults to current datetime if not
provided |
Records stored: inventory_<idx>.
transfer_direct
Direct internal transfer between two locations (single stock move, no transit).
{ "step": "transfer_direct", "product": "PROD-AVG-001", "qty": 5.0, "location": "WH/Stock", "location1": "WH/Output" }
| Field | Required | Description |
|---|---|---|
product |
✅ | Product code |
qty |
✅ | Quantity to transfer |
location |
✅ | Source location (complete name, ilike match) |
location1 |
✅ | Destination location (complete name, ilike match) |
name |
— | Move description (default:
"Internal Transfer") |
date |
— | Scheduled date for the picking in
YYYY-MM-DD format; defaults to
current datetime if not provided |
Records stored: transfer_direct_<idx> (the picking).
transfer_transit
Two-step internal transfer via a transit location. Automatically completes the inbound leg if push rules create it.
{ "step": "transfer_transit", "product": "PROD-AVG-001", "qty": 5.0, "location": "WH/Stock" }
| Field | Required | Description |
|---|---|---|
product |
✅ | Product code |
qty |
✅ | Quantity to transfer |
location |
✅ | Source location (complete name, ilike match) |
name |
— | Move description (default: "Transit Transfer") |
Records stored: transfer_transit_out_<idx>,
transfer_transit_in_<idx>.
consume
Creates an outgoing stock picking (consumption) and validates it immediately.
{ "step": "consume", "product": "PROD-AVG-001", "qty": 2.0 }
| Field | Required | Description |
|---|---|---|
product |
✅ | Product code |
qty |
— | Quantity to consume (default: 1.0) |
Records stored: consume_<idx>.
usage_giving
Creates an outgoing stock picking (usage giving / dare în folosință) and
validates it immediately. Identical to consume but stored under a
different key.
{ "step": "usage_giving", "product": "PROD-AVG-001", "qty": 1.0 }
| Field | Required | Description |
|---|---|---|
product |
✅ | Product code |
qty |
— | Quantity (default: 1.0) |
Records stored: usage_giving_<idx>.
create_invoice
Creates a customer or vendor invoice manually (not linked to a PO/SO).
The invoice is posted immediately unless create_only: true is set.
Single product:
{ "step": "create_invoice", "move_type": "out_invoice", "partner": "customer_1", "product": "PROD-AVG-001", "qty": 2.0, "price": 150.0 }
Multiple products:
{ "step": "create_invoice", "move_type": "in_invoice", "partner": "supplier_1", "products": [ {"product": "PROD-AVG-001", "qty": 2.0, "price": 150.0}, {"product": "MP-001", "qty": 1.0, "price": 200.0} ] }
| Field | Required | Description |
|---|---|---|
move_type |
✅ | "out_invoice" (customer),
"in_invoice" (vendor),
"out_refund", "in_refund" |
partner |
✅ | Partner ref or name |
product |
✅ (single) | Product code |
qty |
✅ (single) | Quantity |
price |
✅ (single) | Unit price |
products |
✅ (multi) | List of {product, qty, price}
objects; also accepts quantity
and price_unit aliases |
invoice_date |
— | Invoice date (ISO format, e.g.
"2026-04-01") |
date |
— | Alias for invoice_date (lower
priority) |
ref |
— | Invoice reference / number (e.g.
"F.1/01.04.2026") |
currency |
— | ISO currency code |
account_id |
— | Account code override for invoice lines |
tax_ids |
— | List of tax names to apply to invoice lines |
key |
— | Explicit key to store the invoice in the execution context |
create_only |
— | If true, the invoice is created
in draft state and not posted |
The created invoice is stored under the auto-generated key
invoice_{move_type}_{safe_ref} (characters /, . and backtick
replaced with _) and also as last_invoice.
post_invoice
Validates (posts) a previously created draft invoice. Resolves the invoice in the following order:
- By explicit
keyin the execution context. - By
refin the execution context (auto-generated keyinvoice_{move_type}_{safe_ref}). - By
reffield in the database (draft invoices). - By
last_invoicein the execution context.
{ "step": "post_invoice", "ref": "F.1/01.04.2026" }
| Field | Required | Description |
|---|---|---|
key |
— | Explicit context key of the invoice to post |
ref |
— | Invoice reference to look up |
create_asset
Creates a fixed asset (account.asset) record.
{ "step": "create_asset", "name": "Laptop Dell", "original_value": 5000.0, "acquisition_date": "2026-04-15", "method": "linear", "method_number": 36, "method_period": "1", "salvage_value": 0.0, "account_asset": "2131", "account_depreciation": "2813", "account_depreciation_expense": "6811", "journal": "Diverse", "validate": true, "key": "asset_laptop" }
| Field | Required | Description |
|---|---|---|
name |
✅ | Asset name |
original_value |
✅ | Gross value of the asset |
account_asset |
✅ | Account code for the asset
(e.g. "2131") |
account_depreciation |
✅ | Account code for
accumulated depreciation
(e.g. "2813") |
account_depreciation_expense |
✅ | Account code for
depreciation expense (e.g.
"6811") |
acquisition_date |
— | Acquisition date (ISO format); defaults to today |
method |
— | Depreciation method:
"linear" (default) or
"degressive" |
method_number |
— | Number of depreciation
periods (default: 36) |
method_period |
— | Period length: "1" =
monthly (default), "12"
= yearly |
salvage_value |
— | Residual value at end of
depreciation (default:
0.0) |
journal |
— | Journal name or code; defaults to first general journal |
validate |
— | If true, validates
(puts in service) the asset
immediately |
key |
— | Explicit key to store the
asset in the execution
context (default:
asset_<idx>) |
create_stock_picking
Creates a stock picking (receipt, delivery, or internal) without
validating it. Use validate_picking to validate it afterwards.
{ "step": "create_stock_picking", "picking_type_code": "incoming", "move_lines": [ {"product_code": "PROD-AVG-001", "quantity": 5} ], "key": "my_picking" }
| Field | Required | Description |
|---|---|---|
picking_type_code |
— | Operation type code:
"incoming", "outgoing",
"internal" (default:
"incoming") |
move_lines |
✅ | List of
{product_code, quantity}
objects |
date |
— | Scheduled date for the picking in
YYYY-MM-DD format; defaults
to current datetime if not
provided |
key |
— | Explicit key to store the picking
in the execution context
(default: picking_<idx>) |
validate_picking
Validates a previously created stock picking (sets all quantities done
and calls _action_done).
{ "step": "validate_picking", "key": "my_picking" }
| Field | Required | Description |
|---|---|---|
key |
— | Key of the picking in the execution context
(default: "picking") |
create_journal_entry
Creates and posts a manual journal entry (nota contabilă) with explicit debit/credit lines.
{ "step": "create_journal_entry", "date": "2026-04-30", "ref": "Salarii aprilie 2026", "journal": "Diverse", "lines": [ {"account": "641", "debit": 10000.0, "credit": 0.0, "name": "Cheltuieli salarii"}, {"account": "421", "debit": 0.0, "credit": 7500.0, "name": "Personal - salarii datorate"}, {"account": "444", "debit": 0.0, "credit": 2500.0, "name": "Impozit pe salarii"} ] }
| Field | Required | Description |
|---|---|---|
date |
— | Journal entry date (ISO format); defaults to today |
ref |
— | Reference / description of the journal entry |
journal |
— | Journal name or code; defaults to first general journal |
lines |
✅ | List of journal lines with account
(code), debit, credit, and optional
name |
key |
— | Explicit key to store the entry in the
execution context (default:
journal_entry_<idx>) |
create_payment
Creates and posts a payment (cash or bank), with optional reconciliation against an existing invoice.
{ "step": "create_payment", "payment_type": "outbound", "partner": "supplier_1", "amount": 600.0, "currency": "RON", "date": "2026-04-15", "journal": "Cash", "memo": "Plată parțială F.5", "invoice_key": "invoice_in_invoice_F_5" }
| Field | Required | Description |
|---|---|---|
amount |
✅ | Payment amount |
partner |
— | Partner ref or name |
payment_type |
— | "outbound" (pay supplier) or
"inbound" (receive from
customer); default: "outbound" |
partner_type |
— | "supplier" or "customer";
auto-derived from payment_type
if omitted |
currency |
— | ISO currency code; defaults to company currency |
date |
— | Payment date (ISO format); defaults to today |
journal |
— | Journal name or code; defaults to first cash journal (or bank if no cash found) |
payment_method |
— | "cash" (default) or "bank" —
used to find the default journal
when journal is not specified |
memo |
— | Payment memo / communication |
invoice_key |
— | Key of the invoice in the execution context to reconcile with after posting |
key |
— | Explicit key to store the payment in
the execution context (default:
payment_<idx>) |
Records stored: payment_<idx> (or key if specified).
Checks Section
Each transactional step can include a checks block to validate stock
state after the step executes:
{ "step": "receive_stock", "checks": { "stock": { "PROD-AVG-001": [ {"qty": 5, "value": 500} ] } } }
| Field | Description |
|---|---|
checks.stock |
Dict of
product_code → [{qty, value, location?}] —
validates on-hand quantity and stock value |
The qty and value in checks are validated as deltas relative
to the initial stock snapshot taken at the start of the scenario. This
means you specify the expected change, not the absolute value.
Optional ``location`` filter:
{ "checks": { "stock": { "PROD-AVG-001": [ {"qty": 5, "value": 500, "location": "all"} ] } } }
| Location value | Description |
|---|---|
| omitted | Validates only the main stock location |
"all" |
Validates across all locations |
"WH/Stock" |
Validates a specific location by complete name |
expected_account_moves Section
Defines expected accounting entries to validate at the end of the scenario.
{ "expected_account_moves": [ { "journal_type": "stock", "line_ids": [ {"account_code": "371", "debit": 500.0, "credit": 0.0}, {"account_code": "408", "debit": 0.0, "credit": 500.0} ] } ] }
| Field | Description |
|---|---|
journal_type |
Journal type to match: "purchase",
"sale", "general", "stock" |
line_ids |
List of expected journal lines |
line_ids[].account_code |
Account code prefix to match |
line_ids[].debit |
Expected debit amount (legacy format) |
line_ids[].credit |
Expected credit amount (legacy format) |
line_ids[].balance |
Expected net balance = debit − credit (preferred format) |
Delta validation: All amounts are validated as deltas
relative to the account balances at the start of the scenario
(snapshot taken at snapshot_stock step). This ensures correct
results even when the database already contains prior transactions.
Using ``balance`` format (preferred):
{ "expected_account_moves": [ { "journal_type": "stock", "line_ids": [ {"account_code": "371000", "balance": 500.0}, {"account_code": "408000", "balance": -500.0} ] } ] }
A positive balance means net debit; a negative balance means net
credit.
Complete Example
{ "id": "ro_stock_avg_case_0001", "name": "[RO_STOCK_AVG] Case 1: Receptie totala, fara factura", "mode": "test", "lines": [ { "step": "create_purchase_order", "product": "product_avg", "qty": 5.0, "price": 100.0, "partner": "supplier_1", "currency": "RON" }, { "step": "receive_stock", "checks": { "stock": { "product_avg": [{"qty": 5, "value": 500}] } } } ], "expected_account_moves": [ { "journal_type": "stock", "line_ids": [ {"account_code": "371", "debit": 500.0, "credit": 0.0}, {"account_code": "408", "debit": 0.0, "credit": 500.0} ] } ] }
Bug Tracker
Bugs are tracked on Terrabit Issues. In case of trouble, please check there if your issue has already been reported.
Do not contact contributors directly about support or help with technical issues.
Credits
Authors
- Terrabit
- Dorin Hongu
Maintainers
Current maintainer:

This module is part of the terrabit-ro/bitshop_ent project on GitHub.
You are welcome to contribute.
Need help getting started?
We are an Odoo partner building apps for the Romanian market (SAGA & WinMentor export; Romanian accounting localization in progress). Direct support from the team that built the module.
Contact Terrabit →
Please log in to comment on this module