Intranet · Annual sales statement
The yearly declaration each store must submit: a 12-month breakdown with totals, moving through unrequested → pending → validated/rejected, with deviation analysis against declared monthly sales, a DMI adjustment, PDF generation and a Yardi upload.
| Area | Intranet |
| Routes | intranet.sales-years · intranet.sales-years.index · intranet.sales-years.edit · intranet.sales-years.show |
| Centre modules | intranet · intranet-yardi |
| Staff levels | root · admin · manager |
| Models | commerce · intranet-communication · intranet-sales-year · yardi-upload |
| UI label | title.header.intranet.sales-years / menu.navbar.sales-years |
| Coverage | 6 use cases · 3 happy · 7 failure |
Known issues (2)
How it works
Management-only (root/admin/manager). The index can enable or disable the statement campaign for all stores (enableSalesYears/disableSalesYears) and flags unvalidatedCommerces — computed by treating only without_sales and validated months as settled, so any store with an unclosed or merely closed month shows up. isEveryMonthValidated gates the year-level validation. The show view adds the deviation level and the DMI value update (the code and translations never expand the acronym), and rejectSaleYear does something notable: it sets the state to rejected and creates an intranet-communication to the store using pre-written subject and message translations, so rejection always comes with an explanation. createPDF produces the signed statement. Navigation note: the side-menu entry for this feature is commented out in utils/get-side-nav-menu.js, so the statement is only reachable through the link to intranet.sales-years.edit on the sales screen or by typing the URL.
Use cases
Why someone opens this (6)
- Collecting each tenant’s annual turnover declaration for rent review.
- Comparing the annual declaration against the sum of monthly declarations to spot deviation.
- Rejecting an inconsistent statement with an automatic notification to the store.
- Updating the DMI value after a negotiation.
- Producing the PDF statement for the lease file.
- Pushing the validated annual figures to Yardi.
Path map
flowchart LR F(["Annual sales statement"]):::feat F --> H1["Statement validated"]:::ok F --> H2["DMI updated"]:::ok F --> H3["Statement rejected with notice"]:::ok F -.-> X1["DMI update fails"]:::bad F -.-> X2["Yardi upload fails"]:::bad F -.-> X3["Rejection communication fails"]:::bad F -.-> X4["Year cannot be validated"]:::bad F -.-> X5["Enable/disable fails"]:::bad F -.-> X6["Role insufficient"]:::bad F -.-> X7["Not discoverable from the menu"]:::bad classDef feat fill:#26688f,stroke:#26688f,color:#ffffff,font-weight:bold classDef ok fill:#e3f1ea,stroke:#0d6b42,color:#0d4a2e classDef bad fill:#f7e6e2,stroke:#9a2d1c,color:#6e1f13
Happy paths
Statement validated
- Manager enables the statement; stores see it as pending.
- A store completes the 12-month breakdown; totals are computed.
- Manager opens the show view, checks the deviation level against monthly sales.
- Every month is validated, so
validateSaleYearsets the state tovalidated.createPDFis used to file the statement.
DMI updated
- Manager opens the update-DMI modal and enters a new value.
updateDMIsaves it andintranet.sales-years.update-dmi-success-messageconfirms.
Statement rejected with notice
- Manager clicks reject; the state is set to
rejected.- An
intranet-communicationis created with the standard reject subject and message and pushed to the store.- The store receives the communication and resubmits.
Failure paths
DMI update fails
Cause — API error.
What happens —
intranet.sales-years.update-dmi-error-message— explicitly says the value was not updated and to contact support.
Yardi upload fails
Cause — API/Yardi error.
What happens —
intranet.sales-years.yardi-upload-error-message.
Rejection communication fails
Cause — The rejection saves but the communication does not.
What happens — A bare
.catch(() => {})— the statement can end up rejected with the store never told, which is the most consequential silent failure in this area.
Year cannot be validated
Cause — Not every month is validated.
What happens —
isEveryMonthValidatedis false andunvalidatedCommerceslists the offenders; the validate action is withheld.
Enable/disable fails
Cause — API error toggling the campaign.
What happens —
.catch(() => {})on the index — silent.
Role insufficient
Cause — Not root/admin/manager.
What happens — The ability blocks the route and hides the menu entry.
Not discoverable from the menu
Cause — The
intranet-sales-yearsmenu item is commented out.What happens — Management users who don’t know the URL or the link on the sales screen cannot find the feature at all.
QA checklist
Tick these off while regression-testing this feature. The boxes are plain Markdown, so progress is visible in git diffs.
- ✅ Statement validated
- ✅ DMI updated
- ✅ Statement rejected with notice
- ⛔ DMI update fails
- ⛔ Yardi upload fails
- ⛔ Rejection communication fails
- ⛔ Year cannot be validated
- ⛔ Enable/disable fails
- ⛔ Role insufficient
- ⛔ Not discoverable from the menu
Implementation
app/controllers/intranet/sales-years/index.jsapp/controllers/intranet/sales-years/edit.jsapp/controllers/intranet/sales-years/show.jsapp/routes/intranet/sales-years/*.jsapp/models/intranet-sales-year.jsapp/abilities/intranet-sales-year.jsapp/enums/intranet-sales-years-states.js
Translation keys (16)
Key English title.header.intranet.sales-yearsAnnual sales statement menu.navbar.sales-yearsAnnual sales statement intranet.sales-years.status.unrequestedUnrequested intranet.sales-years.status.pendingPending intranet.sales-years.status.rejectedRejected intranet.sales-years.status.validatedValidated intranet.sales-years.declaredSales declared intranet.sales-years.deviation-levelDeviation level intranet.sales-years.dmiDMI intranet.sales-years.update-dmi-valueUpdate DMI value intranet.sales-years.update-dmi-success-messageThe DMI value has been updated correctly. intranet.sales-years.update-dmi-error-messageThere was a problem with the updating and the DMI value has not be updated. Please, contact with the support team. intranet.sales-years.yardi-upload-error-messageThere was a problem uploading yardi. Please, contact with the support team. intranet.sales-years.reject-communication-subjectAnnual sales statement rejected, year intranet.sales-years.reject-communication-messageYour annual sales statement presents differences with regard to the sales declared monthly. Please check the amount declared and confirm them again for the following months: intranet.sales-year.button-showValidate annual sales statement
Related
- Same area — Store sales declaration & month closing · Sales status overview & Yardi export · Sales & audit-log CSV download · Intranet communications (threads, confirmations, authorisations) · Communication subtypes · Files management · Footfall (flows) & Yardi upload · SAFT-E - IntelliSales import · Utility consumptions
- Shares data with — Customer receipts tab & ticket-stamp generation · Customer loyalty — coupon exchanges · Receipt verification queue · Store list, filters & exports · Store create & edit · Store CSV import · Activity editor (loyalty mechanics, rules & targeting) · Proposal editor (content, coupon, push, AI images)
- Behind the same module — Store create & edit · Footfall (flows) & Yardi upload · Store sales declaration & month closing · Sales status overview & Yardi export
Generated from doc/feature-inventory.json · id intranet-sales-years · commit 276788ca6