ZRA Smart Invoice — Stock, Traders (Zambia)
by AminiTech Solutions https://www.aminitechsolutions.com$ 293.00
ZRA Smart Invoice — Stock & Traders (Zambia)
Register every product with the Zambia Revenue Authority through your own VSDC (/items/saveItem), then declare each validated transfer as a stock movement (/stock/saveStockItems) under the right ZRA reason code, and push the on-hand quantity to the ZRA stock master (/stockMaster/saveStockMaster) so its ledger matches your books. Losses, breakages and inventory corrections get their own declared, auditable document. Runs on the free ZRA Smart Invoice Base.
One-time purchase · unlimited documents · free updates on every ZRA Smart Invoice spec change. Requires the free ZRA Smart Invoice Base.
Your inventory, mirrored on the ZRA ledger
ZRA wants items registered before they move, movements typed with a reason code, and the stock it believes you hold to match what you actually hold. This app does all three from the Odoo you already run: one click registers a product with its UNSPSC classification and units, every validated receipt and delivery is declared with the correct stock in/out reason on a continuous sarNo series, and the on-hand quantity of each moved product is pushed to the stock master straight after. Everything rides the free Base queue, so a warehouse never waits on a device — and everything goes to your own VSDC or OSDC, with no third-party SaaS sitting in the middle of your tax data.
Register before you move
One click uploads a product to your VSDC with its item code, UNSPSC classification, type, origin, packaging and quantity units, default price, barcode and tax band — and writes ZRA’s own answer back onto the product in plain words.
Every transfer, typed correctly
Validate a receipt and it declares as a purchase (02); validate a delivery and it declares as a sale (11); returns go up as 03 or 12; internal transfers are left alone. The reason code is derived from the operation type, never typed by hand.
Losses, declared honestly
Expired, breakage, loss or discard, inventory increase or decrease — every movement outside the purchase-and-sale flow becomes a numbered ZRA Stock Adjustment with its own sarNo, its own status bar and the VSDC’s verbatim response on the record.
Registration, movements, stock master, adjustments — every step
Every product carries its full ZRA item identity
Each product gains a ZRA Smart Invoice tab holding everything /items/saveItem asks for, split into ZRA Item Identity and Units & Status. Identity carries the item code (itemCd), the item class (itemClsCd), the item type and the country of origin (orgnNatCd); Units & Status carries the packaging unit (pkgUnitCd), the quantity unit (qtyUnitCd), a Registered with ZRA tick and the registration message the device returned. These are the exact values sent on the upload — nothing is improvised at declaration time. The whole tab is scoped to the ZRA User role.
Register a product with ZRA from the product form
Register with ZRA POSTs the product to /items/saveItem through your VSDC with its item code, classification, type, name, origin, packaging and quantity units, tax band, barcode and default price, plus the registrant audit block ZRA requires on every save. A notification tells you what happened straight away — green on success, and a sticky red one carrying the device’s own words when it refuses, so an error cannot be missed. The action sits on a ZRA Item stat button at the top of the product form and works from the product variant too.
A compliant item code, generated if you have none
Leave the item code blank and the app builds a valid one for you rather than refusing: your internal reference if the product has one, otherwise a structured code composed of the two-character origin, the one-digit item type, the packaging and quantity units and a seven-digit sequence — ZM1NTXU0000005 in the screenshot — capped at the twenty characters ZRA accepts. The code is assigned once, on first registration, and reused on every later upload, so your ZRA catalogue and your Odoo catalogue stay pinned to each other. Most catalogues therefore need no extra data entry at all before going live.
Classification that ZRA recognises, defaulted sensibly
The item class is a UNSPSC code (itemClsCd) — 31211500 for the paint in the screenshot — and any product left without one falls back to the company default, itself preset to 99012000, so nothing is ever declared unclassified. The item type follows ZRA’s own list: Raw Material, Finished Product or Service. The country of origin is sent as orgnNatCd and defaults to ZM for Zambia, editable per product — which matters for a merchant importing roofing sheet or solar panels alongside locally bagged cement.
Packaging and quantity units on every declaration
Each product carries a packaging unit (pkgUnitCd) and a quantity unit (qtyUnitCd), preset to NT and U so a fresh catalogue declares cleanly on day one and can be tuned product by product. Both codes travel on the item registration and on every stock movement and adjustment the product appears in, so the device never sees a measure it does not recognise. Anything left unmapped falls back to the safe default rather than being sent empty.
You always know exactly what ZRA said
A Registered with ZRA tick and a registration message sit on the tab, both read-only and both written from the device’s own answer — “Item registered with the ZRA (saveItem): accepted, code 000.” in the screenshot. A refusal is written to the same field verbatim, so you fix the product against what the device actually complained about rather than against a guess. Result codes 921 and 994 — the device telling you it already holds this item — are treated as success rather than as errors, so re-registering an amended product never leaves a false failure behind. Neither field is copied when you duplicate a product.
Register the whole catalogue in one pass
Select any number of products in the list and register them together — cement, rebar, roofing sheet, paint, PVC pipe, mealie meal, solar panels and the delivery service in one go — rather than opening nine forms. Each product is uploaded on its own call and gets its own status and message back, so one refusal does not hide the eight that worked. It is how a new taxpayer gets from a fresh database to a registered catalogue in a single sitting.
16% standard, VAT-inclusive, summed from the lines
A product’s default tax band is read from its sale taxes and declared as a real Zambian taxation-type code — A Standard Rated 16%, B Minimum Taxable Value 16%, C1 Exports, C2 Zero-rating LPO, C3 Zero-rated by nature, D Exempt, RVAT, E or TOT. Amounts go up VAT-inclusive as ZRA requires, with the VAT extracted from the gross rather than added to a net, and the header buckets are summed from the lines so the declaration is internally consistent regardless of how your price list rounds. A product with no tax at all falls back to D rather than failing.
Validate a transfer and ZRA sees the movement
Validating a transfer declares it to /stock/saveStockItems with every moved line — item identity, quantity, cost and tax band — and the reason code derived from the operation type: an incoming transfer goes up as a purchase (02), an outgoing one as a sale (11), and returns as 03 or 12 respectively. Internal transfers and unsupported operation types are marked Not Declared rather than posted as noise. Only lines with a real quantity are sent, and the movement date becomes the occurrence date, so your ZRA ledger moves in step with your warehouse.
One continuous stock-authorization sequence per company
Every movement takes its sarNo from a dedicated no-gap sequence, seeded from the last counter your device reported at initialization so your Odoo series continues where the device left off rather than restarting at one. The number is assigned once per document and reused on every retry, which is what makes an ambiguous resend safe. Continuity matters here: the hourly Base sweep actively checks the declared series for holes and duplicates and escalates if it finds any.
The fiscal state of every transfer, and one click to fix it
The transfer header carries a colour-coded ZRA Status badge — green Declared, amber Queued, red Failed, grey Not Declared — next to a Send to ZRA button that appears only on a done transfer that has not already been declared or deliberately skipped. A ZRA Queue stat button shows how many submissions that transfer has and opens exactly those entries, so you go from a red badge to the device’s verbatim response in two clicks. Ready-made ZRA Declared and ZRA Failed filters sit in the transfers search bar, turning “is anything stuck with ZRA today?” into a one-click answer.
Skip the receipts that must not be declared
A “Declare Receipts to ZRA” switch sits on the purchase order beside the order date, on by default. Untick it and the receipts generated from that order are marked Not Declared instead of being sent — the right answer for a migration load-in or an opening-balance receipt that would otherwise double-count stock ZRA already believes you hold. The check follows the move back to its purchase line, so it holds however the receipt was generated. Everything else declares exactly as usual.
Cancelling in Odoo does not un-declare at ZRA
Cancel a transfer that has already been declared and the app posts a plain-words note in its chatter: the movement is at ZRA, cancelling here does not remove it, and the correct remedy is a counter ZRA Stock Adjustment. It is a small guard against the most expensive mistake in a declared ledger — quietly reversing in Odoo something the revenue authority already has, and only discovering the divergence at an audit. Transfers that were never declared cancel exactly as normal.
The on-hand quantity ZRA holds matches yours
The moment a movement is accepted, the app enqueues a stock-master push (/stockMaster/saveStockMaster) for each product that moved, carrying its current on-hand quantity as rsdQty in that company’s books. That is the call that keeps ZRA’s idea of your shelf aligned with your own — without it, a device that thinks you hold nothing will happily reject a sale of stock sitting in your yard. It happens on its own, after the movement, with nothing to remember.
Declarations land in the order ZRA expects
ZRA requires a sale’s stock-out to follow the sale itself, and answers a premature one with result code 922. Rather than gate anything by hand, the queue treats 922 as a soft dependency and retries it quickly — a minute at a time — until the document it waits on lands, while real errors back off on 5, 15, 45, 135 minutes and up to twelve hours. Entries are always sent oldest-first so your series stays continuous, an entry left mid-send is recovered automatically, and an hourly sweep re-declares any done transfer that was left Failed or Not Declared once the configuration is fixed. Nothing needs a human to notice it.
Declare a loss as a proper numbered document
Every movement outside the purchase-and-sale flow is recorded on a ZRA Stock Adjustment, auto-numbered ZRA-ADJ/00001 from its own sequence, carrying the product, the quantity, the type, a required description, the date and the unit cost — defaulted from the product’s cost and still editable. Declare to ZRA sends it and walks the status bar Draft to Queued to Declared, and the device’s verbatim answer is kept on the record in a ZRA Response block. It is pushed immediately rather than left for the next sweep, and the quantity is always positive: the direction comes from the type, which removes a whole class of sign errors.
Five reasons, mapped to ZRA’s own codes
The type on an adjustment is not free text — it maps directly to the ZRA stock in/out reason code: Inventory Increase to 06, Inventory Decrease to 16, and Loss / Discard, Expired / Obsolete and Breakage each to 15. A builders’ merchant writes down torn cement bags, past-date mealie meal and a dropped tin of paint under the codes ZRA actually publishes, in the words a storeman recognises. The type is tracked in the chatter, so a changed reason leaves a trail rather than quietly rewriting history.
A standing audit trail, and who may change it
The ZRA Stock Adjustments register lives under Inventory and lists the reference, date, product, type, quantity, unit cost and sarNo of every declaration, colour-coded by state — green once accepted, red where it needs attention, grey while still draft. Access is deliberately asymmetric: a ZRA User can see the whole register but cannot create, edit or delete a single record, while a ZRA Manager can — so a declared write-off cannot quietly vanish from the trail. The menu is invisible to anyone without a ZRA role, and a multi-company rule on the queue keeps each entity’s declarations to itself.
We connect you to ZRA Smart Invoice
Buying the app includes the setup: we help you register your device on the ZRA Smart Invoice Taxpayer Portal, point the connector at your VSDC (or ZRA’s hosted OSDC), run the device initialisation, validate the full flow on the ZRA sandbox, then switch you to production.
Device on the ZRA Smart Invoice portal
TPIN, branch, device serial, tax bands
Full flow on the ZRA sandbox
Switch to production, declare for real
One suite, sold your way
Buy only what you need on the free Base, or take the all-in-one Suite.
Frequently asked
Does it need the ZRA Smart Invoice Base?
Yes — the free ZRA Smart Invoice Base holds your TPIN, branch (bhfId), VSDC URL and device serial, runs the initialization handshake and provides the resilient submission queue this app declares through. Install the Base first, then add Stock.
Must products be registered before they move or sell?
Yes — ZRA requires it, and a device that does not know an item will reject movements and sales that reference it. Register each product with /items/saveItem first; movements, sales and adjustments then reference that registered item code.
Does it adjust my Odoo stock too?
No, and deliberately so. A ZRA Stock Adjustment is a declaration to ZRA — you move the actual quantity with the standard Inventory tools, which keeps your books the single source of truth and the declaration a faithful report of them.
Which endpoints does it call?
/items/saveItem for registration, /stock/saveStockItems for movements and adjustments, and /stockMaster/saveStockMaster for the on-hand push. ZRA’s own materials disagree on endpoint pluralization and a wrong path returns 404, so every path is overridable per company as a JSON map — your provisioned VSDC is the only authority.
Any limits or subscription?
None. One-time purchase, unlimited products, movements and adjustments, and free updates on every ZRA Smart Invoice specification change.
Ready for ZRA Smart Invoice compliance?
Install now, or write to us — we set up your Smart Invoice connection with you.
reach@aminitechsolutions.comZRA, Smart Invoice and the Zambia Revenue Authority name are the property of the Zambia Revenue Authority and are used here only to identify the system this connector integrates with. AminiTech Solutions is an independent software vendor and is not affiliated with, or endorsed by, the ZRA.
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Inventory (stock)
• Purchase (purchase) • Discuss (mail) • Invoicing (account) |
| Community Apps Dependencies | Show |
| Lines of code | 2191 |
| Technical Name |
aminitech_zra_stock |
| License | OPL-1 |
| Website | https://www.aminitechsolutions.com |
Odoo Proprietary License v1.0 This software and associated files (the "Software") may only be used (executed, modified, executed after modifications) if you have purchased a valid license from the authors, typically via Odoo Apps, or if you have received a written agreement from the authors of the Software (see the COPYRIGHT file). You may develop Odoo modules that use the Software as a library (typically by depending on it, importing it and using its resources), but without copying any source code or material from the Software. You may distribute those modules under the license of your choice, provided that this license is compatible with the terms of the Odoo Proprietary License (For example: LGPL, MIT, or proprietary licenses similar to this one). It is forbidden to publish, distribute, sublicense, or sell copies of the Software or modified copies of the Software. The above copyright notice and this permission notice must be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Please log in to comment on this module