Files
komp_ac/test_luna
2026-08-21 22:37:30 +02:00
..

Chromium ERP import test

Test the web application as a real ERP workflow in Chromium. Do not begin with a toy CSV. First build and inspect the complete table ecosystem through the web admin. Create each CSV only after its destination schema and all referenced parent rows exist.

Use a disposable database. Log in as superadmin with an empty password.

Start the application and browser

From the repository root:

cargo run -p server -- server

This starts gRPC on [::1]:50051 and the embedded web crate on http://127.0.0.1:3000.

Open an isolated Chromium profile:

chromium \
  --user-data-dir=/tmp/komp-ac-test-luna-chromium \
  --remote-debugging-port=9222 \
  --no-first-run \
  http://127.0.0.1:3000/login

The DevTools targets are at http://127.0.0.1:9222/json. Capture console and Network failures throughout the run.

Build the ERP schema first

Create the tables through /admin/tables/new, in the order below. Use the builder controls for required, indexed, currency, rounding, quantity ledger, column ordering, and row-display columns. After every table creation, verify the redirect selects the new table and that the admin workspace reports the expected types and flags.

Use a unique suffix if these names already exist.

1. Shared units catalogue

Create global table units:

Column Type Options
code text required, indexed, row display
description text required
active boolean required

This exercises global scope. Confirm account, accounting, accounting-transfer, and quantity-ledger choices cannot be applied to a global table.

2. Profile and chart of accounts

Create profile luna_erp with currency EUR by creating chart_accounts:

Column Type Options
account_path account required, row display; automatically unique/indexed
label text required, row display
active boolean required

The account catalogue must be created before any table using accounting or accounting_transfer.

3. Business partners

Create profile table partners:

Column Type Options
partner_code text required, indexed, row display
legal_name text required, indexed, row display
active boolean required
email email_address optional
phone phone optional; inspect generated companion columns
iban iban optional; inspect generated companion columns
payment_card credit_card optional
credit_limit money EUR, half-up rounding
registered_on temporal → date optional
preferred_call_time temporal → time optional
synced_at temporal → instant optional
source_timestamp temporal → raw_datetime optional
payment_window duration optional
contract_period period optional
external_number bigint indexed
risk_score numeric optional

Rename at least one generated PHONE or IBAN companion using the generated-name panel, apply it, and confirm the preview and final table use the alias.

4. Warehouses

Create profile table warehouses:

Column Type Options
warehouse_code text required, indexed, row display
name text required, row display
manager link(partners) required, automatically indexed
unit link(units) required, automatically indexed; cross-scope link
capacity int optional

Confirm links cannot target the table currently being created and that the UI does not offer a redundant manual-index control for a link.

5. Products and quantity ledger

Create profile table products:

Column Type Options
sku text required, indexed, row display
name text required, row display
unit_gtin gtin → 8 optional
case_gtin gtin → 12 optional
retail_gtin gtin → 13 optional
pallet_gtin gtin → 14 optional
supplier link(partners) required, auto-indexed
home_warehouse link(warehouses) required, auto-indexed
unit link(units) required, auto-indexed
sale_price money EUR, exact rounding
purchase_price money USD, half-up rounding
vat_rate decimal(5,2) required
package_count int optional
legacy_id bigint indexed
measured_weight numeric optional
stock decimal(18,3) quantity ledger enabled
active boolean required

Confirm stock is displayed as quantity-ledger/read-only and starts at zero. The import mapper must not offer it as a writable destination.

Create stock_receipts with:

  • receipt_no: required, indexed text and row display;
  • product: required link(products);
  • warehouse: required link(warehouses);
  • supplier: required link(partners);
  • quantity: required decimal(18,3);
  • received_on: required date;
  • processed: int.

Create stock_issues with the same shape, replacing supplier with required customer link(partners), and received_on with required issued_on.

Through /admin/logic/new, attach these scripts:

  • stock_receipts.processed: (quantity-add "product" "stock" (steel_get_column "stock_receipts" "quantity"))
  • stock_issues.processed: (quantity-sub "product" "stock" (steel_get_column "stock_issues" "quantity"))

These tables test three foreign keys per imported row and indirect updates to a read-only quantity-ledger column.

Create sales_orders:

  • order_no: required/indexed text and row display;
  • customer: required link(partners);
  • warehouse: required link(warehouses);
  • ordered_on: required date;
  • status: required text;
  • total: EUR money with half-up rounding;
  • paid: required boolean.

Create sales_order_lines:

  • sales_order: required link(sales_orders);
  • product: required link(products);
  • quantity: required decimal(18,3);
  • unit_price: required EUR money, exact rounding;
  • discount_rate: decimal(5,2);
  • line_position: required int.

This supplies a parent → child → product link chain and composite business rows for import ordering and FK rollback tests.

8. Accounting-only table-definition coverage

Create sales_journal with an accounting definition row, EUR currency, and half-up rounding. Inspect its generated name, tax-point date, debit, credit, and account fields; rename at least one alias and apply it. Add an invoice number and a link to partners.

Create period_transfers with an accounting_transfer definition row and a required text reference.

Confirm each compound definition expands into its managed columns, cannot be indexed, and can only occur once. These tables cover creation-only accounting options. Do not attempt a positive accounting import unless the required accounting periods and accounts have also been configured; otherwise use the expected refusal as an atomic-failure case.

Confirm option/type coverage

Before making CSVs, verify the ecosystem covers:

  • text, boolean, int, bigint, numeric, decimal and money;
  • date, time, instant, raw datetime, duration and period;
  • phone, IBAN, email address and credit card;
  • GTIN-8, GTIN-12, GTIN-13 and GTIN-14;
  • account, accounting and accounting transfer;
  • profile-local, global, and cross-scope link targets;
  • required and optional fields;
  • manual indexes and automatic FK/account indexes;
  • exact and half-up money rounding, with EUR and USD metadata;
  • row-display selection and ordering;
  • generated-column aliases;
  • quantity-ledger and ordinary numeric columns.

If the live backend offers another declarable type, add it to a suitable table and record it. The backend's live type catalogue is authoritative.

Create CSVs last, in dependency order

Only now create CSV files under a temporary directory such as /tmp/komp-ac-test-luna/. Derive every header from the verified table shown in the admin UI. Do not commit fixed parent IDs into this directory.

Import in this order:

  1. units;
  2. chart_accounts;
  3. partners;
  4. warehouses using real partner and unit IDs;
  5. products using real partner, warehouse, and unit IDs;
  6. sales_orders using real partner and warehouse IDs;
  7. sales_order_lines using real order and product IDs;
  8. stock_receipts and stock_issues using real linked IDs.

After each parent import, obtain its inserted IDs from the Analytics page or a read-only database query, then generate the child CSV. Include quoted commas, quotes, Unicode, optional blanks, booleans, money values, dates, and decimal quantities. Use valid GTIN checksums and valid PHONE/IBAN values so a failure is attributable to the feature being tested rather than bad fixture data.

For every import, verify upload → mapping → preview → asynchronous progress → final result. Map by destination name, not blindly with Map in order, because deleted may be the first offered destination and read-only/generated fields change positional alignment.

Required import situations

Successful relational import

Import at least two parents and multiple children. Verify persisted joins:

  • warehouse → manager and unit;
  • product → supplier, warehouse, and unit;
  • order line → order → customer;
  • order line → product.

The displayed link values must resolve to the configured row-display columns, not merely expose numeric IDs.

Quantity-ledger effects

Import receipts for the same product in multiple rows, then import issues. Verify:

products.stock = sum(receipts.quantity) - sum(issues.quantity)

Also confirm stock was never writable in the products import mapping. A failed receipt/issue import must add no quantity contribution.

Mapping and type conversion

Reorder source columns, intentionally ignore one source field, leave optional destinations blank, and use each offered date format. Confirm preview and the canonical prepared CSV agree exactly.

Foreign-key atomic failure

Create a child CSV containing valid rows plus one nonexistent product, partner, warehouse, or order ID. The entire import must fail and commit zero rows and zero quantity-ledger effects.

Validation/type atomic failure

Repeat with one invalid boolean, date, decimal, money, GTIN, IBAN, or required value. Assert the reported CSV row is correct and no partial rows remain.

Multi-chunk rollback

Generate more than 1,000 stock or order-line rows, with an invalid row after the first 1,000. This crosses the import chunk boundary. The final commit must still be atomic: zero imported rows and no ledger contribution.

Schema drift

Prepare a mapping in one tab. In another tab rename, append, or otherwise change a destination column before Preview or Import. The stable column IDs must preserve a rename safely, while removed/read-only destinations must be refused rather than silently retargeted.

Session and concurrency

Try to start a second import in the same session while a large one is running; it must be refused. Confirm a different session cannot poll the first session's job and that logout/session loss is handled without swapping a login page into the progress card.

Pass evidence

Record:

  • Chromium version and console/network failures;
  • every created table and its final column flags;
  • generated aliases and link targets;
  • each CSV header, row count, mapping, preview, and final alert;
  • before/after row counts for successful and failed imports;
  • joined FK results;
  • quantity-ledger balances and the arithmetic that produced them;
  • screenshots of complex mappings, previews, progress, success, and expected failures.

An HTTP 200 or an “Import complete” alert alone is not a pass. The database state, link resolution, atomic rollback, and quantity-ledger effects must agree with the imported ERP transactions.

Executed run and evidence

The staged run was completed against a freshly built server and a disposable database. cargo build -p server passed before the server was started. Chromium logged in as superadmin with an empty password.

The live schema created through the browser was:

  • global units;
  • profile luna_erp: chart_accounts, partners, warehouses, products, stock_receipts, stock_issues, sales_orders, order_lines, journal_entries, and account_transfers;
  • the profile's managed accounting tables (general_ledger, journal_lines, ledger_accounts, and quantity_ledger).

The live tables deliberately cover text, boolean, int, bigint, numeric, decimal, EUR/USD money with both rounding modes, date/time/instant, duration, period, phone, IBAN, email, credit card, GTIN-8/12/13/14, account, FK links, accounting, accounting transfer, generated companions, and a products.stock decimal(12,3) quantity ledger. The stock transaction tables have stock_effect decimal(12,3) computed targets, because a script cannot target its own source quantity column.

The saved Steel scripts are:

(quantity-add "product" "stock"
  (steel_get_column "stock_receipts" "quantity"))
(quantity-subtract "product" "stock"
  (steel_get_column "stock_issues" "quantity"))

The following imports completed and were checked with read-only database queries: partners, warehouses, products, stock receipts, stock issues, sales orders, order lines, chart accounts, and journal entries. Receipt quantity 25.500 followed by issue quantity 20.500 left products.stock = 5.000 and created two quantity-ledger entries. The journal import created one journal row and one general-ledger row. The order-line links resolved through the sales-order and customer/product chain.

The mixed order-line failure (one valid row followed by product ID 999999) reported Link 'product' points to a missing row, inserted zero rows, and left the existing order-line count and quantity effects unchanged. This is the atomic FK rollback checkpoint for the ladder.

Observed failures are part of the test evidence: missing required values are rejected atomically; duration requires an elapsed form such as PT720H, period requires a calendar form such as P3M, and instant requires a timezone-free civil datetime. A missing computed stock_effect is rejected, and the subtraction script expects the positive computed amount while applying a negative ledger contribution. Accounting account values must be paths such as 4000/SALES, not numeric ledger IDs.

Two product issues are also reproducible. Required user columns are displayed as nullable and generated DDL permits NULL even though backend validation still enforces required. The progress card remained at 0% while the backend job had already completed; repeated submissions therefore created duplicate test rows. The final database counts and ledger arithmetic, rather than the stale card, were used as the pass criteria.