# P2 shared products and import checkpoint — 2026-10-20

## Owner decisions accepted
Shared installation-level product identity; company-specific activation/prices/stock. SOH prices include VAT 5%. Warehouse creation is manual. Repeated barcodes may map to multiple distinct products: preserve identities, return candidates and require selection. SKU is the deterministic import identity; mismatch with barcode requires review, never fuzzy matching.

## Implemented and deployed on ERP development only
- Additive migrations 2026_10_20_010000 and 020000: product_masters, product_barcodes, company_products, company_product_prices, product_import_batches and product_import_rows.
- Existing erp_products, media, catalogs, IDs, users and role assignments retained unchanged. No backfill or source data import performed. New and legacy product surfaces remain separate until explicit reconciliation; do not confuse this checkpoint with a finished catalog migration.
- /erp/shared-products: manual shared identity creation, multiple barcodes, duplicate barcode badges, enable for selected company, dated retail/wholesale/van/clearance AED prices. Global master edit/media migration and family/variant management remain pending.
- /erp/barcode-candidates: company-active candidates only, no first-match resolution. Management access currently requires company-wide products.view; scoped sales lookup integration remains future work.
- /erp/import-batches: private source uploads, explicit warehouse selection for warehouse profiles, source effective date, queued analysis, paginated preview, audited explicit row skip, transactional confirmation/replay protection and checksum revalidation.
- Warehouse profile creates/enables product identity and retains quantity evidence only. It does not overwrite prices or post stock. SOH applies prices only to known SKU identities; it does not replace descriptions/quantities. Unknown SKU, identity mismatch, invalid money/quantity or duplicate SKU require review or source correction and re-upload.
- Existing company products and legacy import remain available, clearly labelled in navigation. All new routes enforce matching permission checks.

## Verification
- Isolated SQLite suite: 57 tests / 306 assertions PASS. Coverage: company isolation, barred users, shared identities, ambiguous barcodes, leading-zero string barcode, price separation, zero versus missing, replay, private batch boundary, review gating, source tampering, no warehouse creation and no stock/prices from warehouse quantity import.
- Real MariaDB transactional smoke PASS: two distinct masters sharing barcode, ambiguous candidates, VAT-inclusive price insert; entire smoke rolled back and record count verified unchanged. This is NOT a backup restore drill.
- MariaDB DDL surfaced an overlong auto-generated index name not caught by SQLite. Changed to a short explicit name and resumed partially applied empty DDL without dropping a table. Both migrations applied successfully. Migration retry handles the observed partial state.
- Composer installed PhpSpreadsheet 5.10.0 (latest stable returned by repository, compatible with PHP8.2) plus five-package dependency set; no existing package upgrades/removals, no Composer scripts. Composer audit reports no advisories.
- Parser guidance: https://phpspreadsheet.readthedocs.io/en/latest/topics/reading-files/ . Reader uses bounded 500-row chunks, <=80 columns, no embedded image extraction, no formula execution, cached results only, XLSX XML size preflight, 100k row cap. Numeric Excel identifiers that have already lost leading zeros cannot be reconstructed: source identifiers must be text; further numeric-cell warning coverage remains advisable.
- Reference SOH dry read: 2,089 rows, 2,088 distinct SKUs, one duplicate SKU row with no differences in sampled comparison fields, 26 barcodes shared by distinct SKUs, 12 price precision issues. Peak memory approximately 18MB. This read did not create business records.
- Browser: ChatGPT in-app browser session, desktop approximately 1165px and mobile390x844. Correct titles/content, no error overlay, meaningful empty states, add form expansion, SOH selection hides/disables warehouse, no relevant console warnings/errors. Dedicated Browser plugin absent; existing CUA browser/Playwright-capable session used. No real product submitted via browser. Nonempty production preview rendering/real upload and scanner-device testing remain pending.
- PHP syntax checks and git diff --check pass. No Git commit/push. No Catalog/VAN changes.

## Backups and worker operation
Private backups: /home/snyt/backups/snyt-erp/2026-10-20-p2/before-product-foundation.tar.gz and before-product-foundation.sql. SQL backup checksum bf5e9a316b83912a30d1e23abb31866881431d00bc544ec81475ae20eff8468d. Archive includes pre-phase app/routes/migrations/views/docs/tests/composer files; config/queue.php baseline also remains in Git. Credentials were held in a private temporary defaults file and removed; no secrets printed.
Import queue connection erp_imports has retry_after360; job timeout300; single attempt. Dedicated one-shot worker invocation was validated and exited empty. NO persistent worker or cPanel cron was installed. Do not promise automatic background analysis after upload until a supervised/periodic ERP-only worker is configured. Safe command:
`/opt/cpanel/ea-php82/root/usr/bin/php /home/snyt/public_html/SubDomain/ERP/artisan queue:work erp_imports --queue=erp-product-imports --stop-when-empty --tries=1 --timeout=300`
Persistency/setup remains before user import acceptance tests; no unrelated server process/configuration was changed.

## Required owner decision now — source price precision
12 source values have three decimals, e.g. 79.002, 64.998, 25.002, 6.996, 11.004, 63.999 and 69.996. Current price storage is DECIMAL(14,2) and such rows are deliberately blocked, not rounded.
Recommendation (not accepted): preserve unit prices to four decimals and explicitly round final invoice money to two decimals under a documented line/document tax rounding policy. Alternative: round every imported unit price to two decimals, retaining raw source value and explicit rounding audit. Owner must choose; no lossy conversion was performed.

## Next work after decision
1. Apply chosen price precision consistently to schema/service/manual forms/import validation/formatting and exact-decimal tests.
2. Configure durable ERP-only import worker without altering other applications; test real upload end-to-end privately, corrections/preview and large-file web upload limits.
3. Link/reconcile existing company products to shared masters without silent merges, port gallery/PDF workflows with company access and historical IDs preserved.
4. P3 stock ledger/opening balances/reversal/counted snapshot reconciliation before quantity posting. Clarify ongoing external Focus snapshots versus ERP-as-stock-source workflow before importing quantities as balances.
5. Customers, sales/accounting dependencies, BR-SALES-001 history and remaining phases are NOT complete. Full final user acceptance testing is not reached.

## 2026-10-20 follow-up — preserve source prices, editable per product
This section supersedes the earlier precision-decision blocker. Owner said keep prices as currently present and allow later product-price edits; do not change the workflow to introduce currency conversion. Preserve source unit values up to four decimals, not automatic rounding to two. Existing AED selling-price configuration remains unchanged; no USD purchase-cost or exchange-rate functionality is inferred/implemented. VAT-inclusive5% remains the accepted SOH selling-price rule. Invoice line/document rounding is NOT implemented/approved by this change.
- Applied additive precision migration 030000: gross_amount DECIMAL(16,4), same12 integer digits. Down deliberately refuses destructive scale reduction. Existing source amounts were not converted or bulk imported.
- Updated service/import validation and exact string display; manual inputs accept step0.0001. More than4 source decimals require review, never silent truncation.
- Added /erp/shared-products/{companyProduct}/edit with four independently editable company price types, current values and effective dates; company-scoped404/permissions, audit preserved. Shared library links enabled products to it.
- Tests:61 passed /333 assertions. Includes exact79.002,64.998,6.996,25.1234 persistence/display, too-precise rejection and cross-company detail denial. MariaDB applied migration and saved/read synthetic79.0020 correctly.
- Reference SOH dry read:2089 records, zero price-precision/parser issues after change. Duplicate/identity review remains separate; this does not mean all source rows are import-approved.
- Browser QA at desktop1280x720 and mobile390x844 using existing CUA in-app browser (dedicated Browser plugin absent): correct Product Prices title, populated cards, source79.002 display, editable79.002 input, responsive one-column cards, no framework error/blank page or relevant console warnings/errors. No browser Save submitted. Temporary QA-only product/price created for render inspection and removed via exact guarded fixture cleanup; audit evidence retained. User data and current user tab left unchanged. Synthetic browser screenshot saved to local outputs/erp-unit-price-precision.png and erp-unit-price-mobile.png.
- Backup before changes: /home/snyt/backups/snyt-erp/2026-10-20-price-precision/files-before.tar.gz and database-before.sql (SHA25697e850dd13317bb8e21997c97ab59be444a86c9460512e8269e73f4c36e94f61). Temporary backup credentials/helper and QA helper removed. No source Catalog changes, no push.
Next: durable ERP-only import worker and private upload/review acceptance testing, safe legacy/shared reconciliation, shared media/PDF, then stock-ledger foundation. Full ERP readiness and user final acceptance are still pending.
