Every Odoo product has an active field. When set to False, Odoo doesn't delete the record — it just hides it from almost everything by default (searches, dropdowns, and very likely the RFQ agent's own catalog search, since that's the standard Odoo query convention). The record's data is still sitting there untouched, just unreachable.
Cross-checking all 2,241 product codes in the official price table (tabela-portugal-V26-4.pdf, V26.4) against a full Odoo pull (active + archived) found 719 codes (32%) where Odoo's price matches Tabela's price exactly, but the Odoo record is archived.
Examples (live-verified against Odoo 2026-07-05), spanning cheap and high-value products alike:
| Code | Product | Odoo price | Tabela price | Category | active |
|---|---|---|---|---|---|
ILAR-00230 | 1.5W Lâmpada G4 LED 4000K | €1.67 | €1,67 | G4 & G9 | False |
ILAR-02003 | 1000W Projector TECH II 15º-OP02 5000K 0-10v | €1,476.61 | €1476,61 | Tech II | False |
ILAR-01925 | 15W Project Strip 12x4mm 120Led/m 3000K 100m IP65 | €1,995.83 | €1995,83 | Project Strip 230V | False |
ILAR-02224 | 90W Aura D1500mm 3000K/4000K/5000K 3CCT IP42 | €834.60 | €834,60 | Aura Circular | False |
The exact price match is the key signal: if this were a genuinely discontinued product, nobody would have bothered keeping its Odoo price in sync with the current price table. The fact that it matches perfectly strongly suggests these 719 products are still meant to be sold, and got archived by accident — not a deliberate discontinuation. This isn't limited to cheap accessories — €1,476 and €1,995 items are affected too.
Smoking gun for question (b): checked write_date on all 719 records directly in Odoo. 711 of 719 (99%) were last modified on the exact same day — 2026-07-03 (the remaining 8 on 2026-06-30). This is not 719 independent accidents — this is one single bulk operation that archived nearly all of them at once, one day before this analysis was run.
(c) is now CONFIRMED via code, not just inferred from data — checked directly against Adapt-to-AI-B2B/aronlight:
- The Odoo→Django sync (
backend/catalog/management/commands/sync_products.py:12) queries withBASE_DOMAIN = [['sale_ok', '=', True]]and never passesactive_test: Falseor an active-inclusive domain (confirmedbackend/catalog/odoo_client.pynever sends acontextat all). Archived products are never even pulled into Postgres, full or incremental. - The local mirror table
OdooProduct(backend/catalog/models.py:7) has its ownactivefield, but the sync's reconciliation step (sync_products.py:183-197) force-deactivates any locally-active row not returned by the last Odoo sync. - The matcher (
backend/catalog/rag.py) filters onactive=Trueredundantly at every candidate path: line 100 (register lookup), line 134 (SKU-match tiers 1/2), and line 188 (_exclude_junk(), the shared choke point for vector search, lexical search, and fuzzy SKU match). - The only place that explicitly asks Odoo for archived rows is
product_status.py'slive_inactive_skus()— but that only re-checks already-surfaced candidates, it never discovers new ones. It can't recover these 719.
Net effect: confirmed, not hypothetical — all 719 products are unreachable by the RFQ agent today, at three independent layers. Fixing Odoo alone (bulk active=True) is necessary but not sufficient — a re-sync also has to run afterward.
Remaining questions for Ricardo/Manel:
- (a) Can you confirm whether these 719 products should be active? If yes, this looks like a single bulk
active=Truefix in Odoo rather than 719 individual product reviews. - (b) What ran against Odoo on 2026-07-03? Given 711 of 719 were touched that exact day, this is almost certainly traceable to one specific operation (migration, bulk edit script, category cleanup) — a much narrower question than "why are these archived" in general.
Priority: HIGH — this is the same failure mode as OD-2 (products invisible to the agent), but ~48x larger in scale (719 vs. 15), and now confirmed at the code level rather than inferred.
OD-3 surfaces the concrete version of this question, but it's really a more general policy question underneath the whole Tabela-vs-Odoo reconciliation: when the official price table (tabela-portugal-V26-4.pdf) and Odoo disagree, which one is Aronlight's actual source of truth?
· Price and active/inactive status: Odoo wins, unconditionally — Tabela is never even read. sync_products.py only pulls sale_ok=True products with no active context passed. The matcher (rag.py) filters active=True redundantly at three points. This is exactly why OD-3's 719 products are invisible — Tabela's price is irrelevant to the agent, only Odoo's active flag matters, and it says no.
· Category hierarchy and a few attributes: Tabela wins, where it has coverage. manage.py ingest_pricetable reads the extracted price-table JSON and writes pricetable_section/category/subsection/subcategory (finer-grained than Odoo's flat category), plus fills kelvin/ip_rating/lumen/reel_length_m — only where blank; Odoo-sourced values are never overwritten. Also seeds accessory-pairing suggestions from Tabela's own groupings.
· Coverage is partial and Portugal-only today. Only one tabela file has ever been ingested — catalog/extracted/tabela-V26.4.json. No Italy or Spain equivalent exists yet (relevant to aronlight#397). ~40% of active products aren't in the price table at all.
So the real answer today is a split, not a single policy: Odoo is authoritative for price and existence; Tabela is authoritative for category/attribute detail, but only fills gaps, and only for Portugal.
(a) Is this split intentional, or accidental (Tabela ingestion was built for category/attribute enrichment and simply never extended to price/active status)?
(b) For OD-3 specifically: should Tabela's presence ever override Odoo's active=False, given the split above currently says no, but OD-3's own evidence (99% of the 719 archived on one single day) suggests the archiving itself may have been the mistake, not a deliberate discontinuation?
(c) Should Italy/Spain get their own ingest_pricetable-style JSON once #397 extracts their tabelas, using the exact same mechanism already built for Portugal?
Priority: HIGH — this is the governing question behind OD-3, OD-2, and the price-mismatch findings all at once. Without (b) specifically, OD-3's fix is still a guess about direction.
The agent pre-filters catalog search by Odoo category. Products with no category assigned (UNCATEGORIZED) are completely invisible to semantic search — they can only be found when a customer writes the exact Aronlight SKU. Evidence from eval corpus run 2026-07-01 (13 real RFQ cases).
Tier 1 — HIT on direct SKU in multiple real RFQs, but MISS when customer describes by spec:
| SKU | Product | Evidence |
|---|---|---|
ILEM-00034 | SafeLux P/NP 3H Selftest 6000K IP65 200lm | HIT in cases #15, #31, #37, #39 · MISS in case #24 (spec search) |
ILAR-00469 | Perfil de Alumínio de Superfície 2M Opal IP20 | HIT in case #31 · MISS in case #44 |
Tier 2 — quoted by rep as correct match, never surfaced by the system (case #44):
| SKU | Product | Qty requested |
|---|---|---|
ILAR-02396 | BEN 10W 2700K/3000K/4000K 3CCT IP20 | 14 |
ILAR-02398 | Lente BEN 36º | 14 |
ILAR-02638 | BEN KIT IP65 | 14 |
ILAR-02565 | 48W Dura PRO 150cm On-Off Linkable 4000K IP69K | 6 |
ILAR-02385 | PETI 5W 2700K/3000K/4000K White 3CCT IP65 | 4 |
ILAR-02386 | PETI 5W 2700K/3000K/4000K Black 3CCT IP65 | 1 |
ILAR-02449 | Miranda 40W D460mm 3CCT IP44 | 6 |
ILAR-02796 | Prado M 15W 36º Branco 3000K IP20 | 10 |
ILAR-02868 | Pini Round 3W Branco 3000K | 1 |
ILAR-03360 | 48V 20mm Calha encastrada 2m Preto | 3 |
ILAR-03372 | 48V 20mm Módulo de ligação reto Preto | 2 |
ILAR-03391 | 48V 20mm LINEAR DOT L112 6W 36º 2700K Preto | 12 |
ILAR-03668 | CIMA Caly H350 8W 3CCT | 13 |
Action required: assign an Odoo product category to each SKU above. The category name determines which search bucket the agent uses (e.g. "Painéis LED" → PANELS, "Projetores" → SPOTLIGHTS, "Armaduras Emergência" → EMERGENCY, "Perfis Alumínio" → PROFILES). Without a category, the agent will miss these products on every spec-based RFQ regardless of how well the rest of the system works.
Priority: HIGH — 15 products actively quoted by reps but invisible to the agent. Each one is a guaranteed MISS on any spec-based search.
Consolidated 2026-07-06 from four former separate entries (CLI-1, CLI-2, CLI-3, PROC-1) — all facets of one gap: nobody has documented how an RFQ actually moves from inbox to sent quote today, or who does each step.
1. Internal team map — who does what
We know some names from emails (jose.moreno@aronlight.es, flavio.monteiro@aronlight.pt) but not their roles or how the workflow splits between them.
· Jordi Marco — jordi.marco@aronlight.es — Delegado Comercial (central / south Spain)
· Samuel Del Valls — samuel.delvalls@aronlight.es — ES channel
· José Moreno — jose.moreno@aronlight.es — Director Comercial ES
· Javier Soler — javier.soler@aronlight.es — northern Spain (Basque Country / Navarra, confirmed 2026-06-20)
(a)/(b) Sales team / Back office team — names + emails? — PARTIALLY ANSWERED, 2026-07-08. Live Odoo pull gives all 30 people who've created a sale.order: Carla Santos, Tiago Timóteo, Adriana Fernandes, Alexandre Videira, Ana Moura, Ana Sousa, Ayelen Montenegro, Flávio Monteiro, Jorge Molina, José Monteiro, Jose Moreno, Manuel Vidigal, Mario Antunes, Monica Picilli, Nuno Cruz, Patricia Gutierrez, Paulo Silva, Raquel Souza, Ricardo Silva, Saad Sanhadji, Sebastien Raynal, plus more. Still open: this is who creates orders, not an official role tag — see (c) for the overlap.
(c) Does sales ever create proposals in Odoo, or always back office? — ANSWERED. Both: agents route through back office, but salespeople with direct Odoo access (Samuel, Jorge Molina, Patricia) build their own. See docs/faq-answered.md § Process routing.
(d) Full process map — Who receives it → who decides PT or ES → who does the product lookup → who creates the sale.order → who sends the quote?
(e) Internal forward pattern — Standard subject prefix or convention when a rep forwards internally?
(f) consultas@ and pedidos@ — Shared inboxes or aliases forwarding to individuals? Who monitors each?
2. ARONLIGHT ESPAÑA SL — internal channel workflow
Single largest source of proposals in staging: 796 proposals in April-June 2026 (265/month), 90% conversion, €511K. Internal Portugal→Spain requests, not external clients — each creates a sale.order in Odoo PT. Routing appears to be client → regional ES rep → PT back office (Flávio primarily) → proposal → back to ES rep → client, but not formally documented.
(g) Full routing sequence. — ANSWERED. See docs/faq-answered.md § Process routing for the full client→quote chain, including the invoicing mechanic.
(h) Who at ES can submit RFQs to PT? Besides the 4 above?
(i) Odoo or email? Should the agent create a real sale.order for Spain requests, or a draft emailed to the ES rep?
(j) Pricing. Does Spain use the same pricelists as external PT clients, or an internal transfer price?
(k) Volume trajectory. Is 265 proposals/month typical, growing, or shrinking?
3. High-volume distributors — is there a different process?
| Client | Proposals | Conversion | Value |
|---|---|---|---|
| CONTERA | 229 | 93% | €91K |
| HIPOLOESTE, SA | 88 | 65% | €164K |
| ARMASUL, SA | 85 | 64% | €118K |
| LEMELUZ, LDA | 77 | 82% | €51K |
| STRADA, LDA | 74 | 78% | €59K |
| SONEPAR PORTUGAL | 45 | 24% | €184K |
(l) Dedicated contact? Does CONTERA (229 proposals) have a dedicated Aronlight rep?
(m) SLA. Do high-frequency clients get faster turnaround (same-day vs. standard 48h)?
(n) Pricelists. What discount tier does each of these clients use? — ANSWERED — duplicates PRICE-1, resolved 2026-06-19. CONTERA = custom, HIPOLOESTE/LEMELUZ = 52% + Liquidos, ARMASUL = 48% + Liquidos. No shared "distributor standard."
(o) Channel. Do they email a personal address, a shared inbox, WhatsApp?
(p) SONEPAR handling. 24% conversion suggests price-shopping. Does the team deprioritise them?
(q) Client taxonomy. Internal vs. distributor vs. contractor — does Aronlight treat them differently today?
4. "Consultas" centralisation — what should it look like?
(r) Inboxes today. Which addresses currently receive client RFQs? Personal (flavio@, carla@, jose@)? Shared (consultas@, pedidos@)? Both?
(s) Routing rules. Do high-volume clients have a designated contact, or email whoever they have a relationship with?
(t) CONTERA concretely. How does CONTERA send a request today? One email with 50 items? Ten emails of 5? WhatsApp?
(u) Portal today? Any client self-service portal, or everything by email?
(v) Ideal design. Single inbound address (rfq@aronlight.pt), per-client subdomain, API, WhatsApp number?
Update 2026-07-06: subsections 2's (h)/(i)/(j) answered directly by Adriana Fernandes (agent/salesperson/end-client order sources; full Spain dropship + invoicing mechanic), plus two new findings — (5) "proposal" counts throughout this research are raw sale.order records, not business-sense quotes (she estimates real quotes at only a few/week); (6) Italy and likely France work through Aronlight's own external agents, not direct clients, with no separate company entity in Odoo for either. Full detail in docs/faq-open.md and docs/calls/2026-07-06-*.md.
Update 2026-07-08: (k) partially answered — live Odoo pull confirms the ARONLIGHT ESPAÑA channel breaks down as Adriana Fernandes 71% (1,647 of 2,319 orders), Ayelen Montenegro 14%, Raquel Souza 9%, plus 4% from the automated OdooBot account. Adriana's own call confirms her declining trend (372→204/month) — but why is still open, never actually answered on the call. (l) answered empirically for all 6 distributors — no single client besides LEMELUZ (Tiago Timóteo 67%) and STRADA (Carla Santos 66%) has anything close to a dedicated rep; CONTERA, HIPOLOESTE, ARMASUL, and SONEPAR are all split across 3-4 people. SONEPAR's even split (nobody above 29%) is consistent with its low 24% conversion — no one person owns that relationship.
Priority: HIGH — foundational, not a bug fix. 796 + 553 proposals/quarter together represent the majority of Aronlight's quote volume by record count, and none of it can be correctly automated until routing, roles, and intake are understood. Blocks the @aronlight.es sender-detection design (case 17) specifically.
The matching engine needs hard cutoffs. Proposed values below based on Jun 2 call + industry practice. Please confirm or adjust each row.
| Spec | Proposed rule | Source | OK? |
|---|---|---|---|
| Lumen | ≥ spec (no upper cap) | Jun 2 call | ✓ |
| Wattage | ≤ 2× spec — reject if more than double | Jun 2 call (30W→60W = rejected) | confirm |
| IP | ≥ spec (no upper cap) | Jun 2 call | ✓ |
| CCT | ±200K tolerance | Estimated — not discussed | confirm |
| CRI | ≥ spec CRI if stated; ≥ 80 default | Jun 2 call (important, no threshold) | confirm |
| IK | ≥ spec if stated; ignore if not stated | Not discussed | confirm |
| Dimensions (recessed) | Cutout size ≥ spec; outer ≤ spec + 10mm | Jun 2 call ("não pode ser mais pequeno") | ✓ |
| Dimensions (surface) | ±15% accepted | Estimated | confirm |
Some Aronlight products are sold as 3CCT or tunable white (e.g. ILAR-03294 Nexa 50W 3000K/4000K/5000K). When an RFQ asks for the product without specifying CCT (case 20 Voltel did exactly this), what should the agent assume?
Quote at 4000K (industry standard for public/commercial/industrial lighting) and add a single-line note in the quote: "CCT default: 4000K — confirm or specify 3000K/5000K if needed." Reviewer can override before sending.
Alternative: withhold the quote and auto-reply asking the client to specify CCT first.
We are proposing 4000K because the real case 20 quote shipped without CCT specified — implying the team is comfortable letting the client clarify after. Blocking on every multi-CCT RFQ would slow down the standard distributor flow significantly.
Confirm the 4000K default, propose a different value, or tell us to ask the client every time.
From RFQ #109 (Alfilux ORCLB2600497), IT01.1: inbound specified 3000K (TUBOLINE SALI 35W 30K), but Flávio quoted 4000K (Dura PRO IP69K 4000K). This appears to be a deliberate application-driven choice, not a catalog gap.
- (a) Are there room types or applications where the agent should always override the specified CCT (e.g. kitchens → 4000K, food processing → 4000K regardless of request)?
- (b) If yes, is there a list of keywords in the product description, project title, or room type that trigger a CCT override?
- (c) When the agent overrides CCT, should it flag the change explicitly in the quote note, or is it expected silently?
Client asked, verbatim: "15un Projectores LED IP65 de 150W, 6000K ou 6500K" and "15un Projectores LED IP65 de 250W, 6000K ou 6500K." Carla's real quote (OR 2026/15665) used the Master Pro family at 5000K for both lines — ILAR-00983 (150W, correct wattage) and ILAR-00985 (300W, not the requested 250W).
This time we can rule out "the agent would have missed it anyway": the RFQ agent's own automatic matcher, working from the identical request text, correctly excluded 5000K products as out-of-spec and surfaced a 6000K-compliant alternative instead (ILAR-02891, Spectra family, correct wattage, €59 vs Master Pro's €165). Carla didn't fill a gap the agent couldn't see — she chose a product the agent had already (correctly, per the stated CCT) ruled out. This diverges from the request on three axes at once: CCT, product family/optic (Master Pro's asymmetric "Asy-OP01" vs. the cheaper Spectra that matches spec), and on the 250W line, wattage too.
1. Na linha dos 150W: o cliente pediu 6000K ou 6500K, mas a proposta tem 5000K. Foi porque não existe opção de 6000K/6500K no Master Pro, ou já sabias que este cliente aceita 5000K?
2. Ainda nos 150W: porque escolheste o Master Pro (€165) em vez de um projetor mais barato que já tem 6000K disponível? Tem a ver com o feixe/ótica (Asy-OP01), ou outra razão?
3. Na linha dos 250W: o cliente pediu 250W, mas a proposta tem 300W. Não existe opção de 250W nesta gama, ou foi decisão tua subir para 300W?
Priority: HIGH (bumped from MEDIUM) — now two independent back-office staff (Flávio, Carla), two different clients, same underlying pattern: CCT deliberately overridden with no visible system flag, this time confirmed the agent itself had a spec-compliant alternative available. If this substitution is standard practice, it needs to become an explicit matching rule — not left as an unmodeled deviation that looks like a matcher bug every time we eval a real quote.
From RFQ #109, IT01.1: inbound product had no IP specification, but Flávio chose IP69K (food processing / high-pressure washdown grade). Nothing in the email or line text indicated this — it appears to come from knowledge of the product family ("SALI" = kitchen/washdown context).
- (a) Are there product families or description keywords that always imply a minimum IP grade regardless of what the customer specifies? (e.g. "SALI" → IP69K, "exterior" → IP65 minimum)
- (b) Is there a mapping of installation context → minimum IP we could encode as a rule? (e.g. food processing = IP69K, exterior = IP65, bathroom = IP44)
- (c) If the customer specifies a lower IP than the application requires, should the agent flag this and suggest the correct IP, or silently upgrade and note the change?
Rule 1 logic: sum(length_m × W/m per SKU) × 1.20 → pick smallest PSU that covers it. W/m values calculated from Odoo catalog (2026-06-20) — please confirm or correct:
| SKU family | Product type | Calculated W/m | Source | OK? |
|---|---|---|---|---|
ILAR-00620–00625 | ProStrip 24V monochrome 5m | 2.9 W/m | 14.4W ÷ 5m | confirm |
ILAR-00638 / 00831 | ProStrip RGB 24V 5m | 2.9 W/m | 14.4W ÷ 5m | confirm |
ILAR-03159–03164 | Fita Led ST 8mm 60Led/m 5m | 1.0 W/m | 4.8W ÷ 5m | confirm |
ILAR-03174–03181 | Fita Led ST 8mm 140Led/m 5m | 2.4 W/m | 12W ÷ 5m | confirm |
ILAR-03182–03189 | Fita Led ST 8mm 180Led/m 5m | 2.9 W/m | 14.4W ÷ 5m | confirm |
ILAR-03190–03197 | Fita Led ST 10mm 240Led/m 5m | 3.8 W/m | 19.2W ÷ 5m | confirm |
230V strips (SlimStrip AC, Project Strip 230V AC): Rule 1 does NOT fire. These products say "230V AC" in the product name and run direct from mains — no PSU needed. Confirmed from Odoo catalog.
Still needed: any strip SKUs missing from this table (e.g. ILAR-01404 COB PRO — no clear length in name), and confirmation these W/m values are correct.
Suggest profile only when order includes strip AND project description mentions a visible install location (no "industrial", "warehouse", "trunking", "canaleta" keywords).
Or should the profile always be suggested and the reviewer removes it?
Monochrome (width unspecified): suggest ILAR-03322 (10mm) + note "8mm variant ILAR-03314 also available — confirm strip width."
RGB strip ILAR-00638: always ILAR-00641 (4-pin RGB connector).
Is ILAR-03322 the right default? Any missing connector SKU?
If order has ≥ 5 luminaires and no ILEM- SKU → suggest "have you included emergency lighting?"
If order has only ILEM- SKUs and no luminaires → flag for reviewer (standalone emergency or retrofit?).
Is the 5-luminaire threshold right, or should the flag fire on any commercial order regardless of count?
| # | Trigger | Suggests | Qty | Status |
|---|---|---|---|---|
| R5 | Panel 300×1200mm ILAR-02979 | Aro frame ILAR-00508 | 1:1 | HIGH — confirm |
| R6 | Thane pendant ILAR-00711 | Suspension kit ILAR-00713 | 1:1 | HIGH — confirm |
| R7 | GU10 lamp (recessed) | Aro trim ring | 1:1 | How to detect recessed vs track? |
| R8 | DALI luminaire | DALI driver | 1:1 | HIGH — confirm |
| R9 | Panel 300×600mm ILAR-01774 | Bracket ILDV-00032 | 1 per 2 panels? | Confirm ratio |
| R10 | Meller body | Espelho trim ring | 1:1 | HIGH — confirm |
In the Alfilux proposal (ORCLB2600497), bundles are priced with a single "DVDI" placeholder line at full price, and all sub-components listed at €0.00001. Examples: IT05 (CONJUNTO PERFIL MICRO 38 + FITA LED 14.4W) and IT16 (CONJUNTO PERFIL DELTA SPM20).
"DVDI" is not a product reference — it is an Alfilux-internal pricing code meaning "no direct equivalent / bundle." The agent currently cannot parse this structure.
- (a) When we see a DVDI-priced bundle, should the agent match the sub-components individually and build the Aronlight equivalent? Or treat the whole block as a single custom line?
- (b) Is "DVDI" specific to Alfilux, or do other distributors use the same convention?
- (c) For IT05 (LED strip profile bundle), the correct response required summing individual run lengths from a note field and sizing PSUs from that total. Is this the standard approach for all LED strip bundles from distributors?
From RFQ #109: two different Onlight products (OHONCSHOOT.13, IT02 and OHBBEQSRM.13, IT09) both mapped to ILAR-03699 (GABI D65 5W). Flávio quoted them as separate lines (6 units and 4 units), not consolidated to one line of 10. IT02 was also reduced from 10 to 6 — the remaining 4 appear to be covered by IT09.
- (a) When two inbound items map to the same Aronlight SKU, should the agent keep them as separate lines or consolidate into a single line with summed qty?
- (b) IT02 was quoted at 6 units, not the requested 10. The remaining 4 appear covered by IT09 (same SKU). Should the agent understand this split, or always quote 1:1 on quantity?
- (c) Is there a rule for when same-SKU consolidation applies vs. when items should stay separate (e.g. different rooms, different circuits)?
When an email arrives with an empty body ("ver anexos") and the attachment is unreadable (corrupted, expired link, wrong format):
Auto-reply to sender: "We received your request but could not read the attachment. Please resend directly as PDF or Excel." Log the email in Odoo with a note. No manual team notification.
Or should the team always be notified so they can follow up personally?
Case 19, Saltoki: "50 metres of ILAR-01691 neon RGB tube." Product sold in 5m reels → 50m = 10 reels, each needing a PSU.
Parse reel length from product name (e.g. "5M" → 5m per reel) and calculate reel count + PSU count automatically.
Is reel length always in the product name? Are there other strip/tube SKUs sold by reel we should know about?
Some RFQs (e.g. case #44, Alfilux with Delta/Onlight/Drees products) contain only competitor brand codes where Aronlight carries the category but not the brand. The agent always returns a suggestion for every line — all flagged needs_review — but the rep must dismiss each one individually. For a 50-item cross-brand RFQ this creates significant friction.
Two options:
- Option A — Suppress: when no confident equivalent is found, return "no equivalent found" and leave the line blank. Rep fills manually.
- Option B — Flag: always show the best candidate found, clearly marked "requires verification — competitor brand not in catalog." Rep uses it as a starting point.
- (a) For a cross-brand RFQ like the Alfilux example, does Flávio prefer to start from a blank line (Option A) or a flagged suggestion he can reject (Option B)?
- (b) Is there a confidence threshold? E.g. show when ≥70% confident, suppress below?
- (c) When Aronlight carries zero equivalent in a product category (e.g. a specific driver brand not stocked), should the agent flag as "catalog gap" or leave blank?
Priority: MEDIUM — already tracked in GitHub as #237 (P2, open), so it's on the engineering backlog independent of this FAQ. Downgraded 2026-07-06.
A proportion of RFQs from distributors (e.g. Alfilux, Victor Silva) arrive as: "Em anexo, enviamos uma proposta da [Brand] — é possível dar-nos o equivalente?" The email body contains no project description, no room types, no installation context. All product information is in the PDF attachment.
This pattern makes every context-based matching improvement irrelevant — installation_context is always "unknown" for this RFQ type.
- (a) What percentage of Aronlight's inbound RFQs are distributor "equivalent" requests with no project context?
- (b) For these RFQs, what is the correct agent behaviour: pure spec-for-spec substitution (match on wattage, IP, CCT only), or flag missing context and ask the distributor to provide it?
- (c) Do distributors ever provide context on request, or is it typical to expect a straight equivalent without discussion?
- (d) For distributor RFQs, does Flávio still apply application-based overrides (IP uprating, CCT change) — or is it always a strict spec-for-spec match?
Case 16: Aura Light BOGT3 and MILA M appear discontinued — no current datasheet online.
Work from whatever specs the customer provided in the email. If specs are incomplete, flag the item as "insufficient spec — team to verify" and include it in the partial quote with a note. Do not block the whole quote.
Does Aronlight have an archive of competitor datasheets we could query?
Case 07, Biobanco Azul: 8 items with Lum_A01.x codes. Only 1 of 8 identifiable.
Process the 1 identified item, quote it, reply with: "We identified 1 of 8 items. The remaining 7 use internal project codes. Please send the caderno de encargos to complete the quote." Do not wait for the full spec.
Confirm: partial quote + explicit list of unmatched items = correct response here?
Case 13: customer describes a technical installation problem but does not ask for a specific product.
Route to technical specialist immediately. The agent does not infer a product need from a problem description.
Who is the technical routing contact in PT and ES?
Aronlight publishes a public product catalog at aronlight.com/catalogo/aron-catalog. It is not yet documented how this page and "Tabela" fit into the quoting workflow described elsewhere in this doc (Odoo pricelists — see PRICE-2, DISC-1).
- (a) Is
aronlight.com/catalogo/aron-catalogused internally by sales/back office when preparing a quote, or is it a client-facing page only? - (b) What is "Tabela" in this context — a price list separate from the Odoo pricelists, a printed/PDF catalog, or another document? Is it the same thing as the public Catalog page, or different?
- (c) If Tabela and/or the public Catalog are sources of truth for product info or pricing, does the agent need to read them directly, or is everything already mirrored in Odoo (
catalog.jsonexport)?
Priority: MEDIUM — need to know if this is a separate system for pricing/catalog info or already covered by Odoo (see PRICE-2, OD-1, OD-2).
Some inbound RFQs arrive as a formal BOQ position code with no functional spec and only a bare label, e.g.:
8.1.5.1.1.1 L2 89 un Com
No wattage, CCT, IP, or descriptive text beyond "Com" is given, yet the resulting quote line matched it to:
[ILAR-01960] 150W Campanula Master II 3CCT 3000K/4000K/5000K IP65 — 89 Unidades @ €68,7480 — Total €6.118,57
- (a) What information actually determined this match — the BOQ position code itself (
8.1.5.1.1.1), a caderno de encargos / project spec sheet referenced by that code but not included in what was sent, or prior knowledge of this client's or project's typical spec? - (b) Is the position code meaningful on its own — does it map to a recurring catalog of BOQ line types Aronlight has seen before, or is it project-specific and only resolvable by reading the full caderno de encargos?
- (c) For the agent to replicate this, what does it need beyond the bare RFQ line — should it always request the full caderno de encargos when a line arrives as a position code with no spec, or is there a faster process used in practice today?
Priority: MEDIUM — this pattern is currently a single observed example; downgraded 2026-07-06 pending Flávio's answer on whether it's common enough to justify architecture work.
From the Ayelen Montenegro call (2026-07-06): today, a client with unpaid invoices isn't flagged when an order is loaded. The whole order gets entered, stock gets checked, everything proceeds normally — and only at the very last step ("validate the pick," right before dispatch) does a pop-up warn the client is blocked for outstanding debt. Concrete example: an order for Adichem SRL (forwarded by an agent) got stuck this way; she had to manually notify the agent afterward that the client owes money and can't be shipped until resolved.
- (a) Is client credit/debt status available as a field the agent could check before processing a line, rather than discovering it only at pick-validation?
- (b) If detected upfront, what should the agent do — hold the whole order, process everything except that client's lines, or flag it for the rep to decide?
- (c) Is this specific to the Italy agent-mediated flow, or does the same late-surfacing behavior apply to all markets (PT, ES)?
Priority: MEDIUM — real, live workflow gap reported directly by the person doing the job; causes rework and manual client notification after the fact.
Case 20 (Voltel, 2026-06-15) showed that real quotes include stock alerts inline: "Artigo indisponível — previsão de entrega: 13/7/26." The agent must replicate this — silently quoting an out-of-stock product is worse than not quoting it.
1. Read qty_available (or equivalent free-stock field) for each SKU at the active company (PT = company_id=3, ES = company_id=2).
2. If qty_available < requested_qty, attach to the line: "Stock insuficiente — previsão de entrega: [date]."
3. ETA comes from supplier lead time (product.supplierinfo.delay or seller_ids[0].delay) counted forward from today.
(a) ✓ Proposed: use free_qty ("Free To Use Quantity" = on-hand minus reservations). Verified in Odoo staging: ILAR-03294 = 103 units free. Correct, or do you read a different concept?
(b) ✓ Proposed: read product.supplierinfo.delay (supplier lead time in days). Voltel case (OR 2026/13707, emitted 2026-06-15, ETA 2026-07-13) suggests ~28 days lead time, consistent with a stored value. Correct, or do you check manually?
(c) ✓ Proposed: two separate lines, matching the Voltel pattern — one line for the in-stock SKU + one line for the out-of-stock alternative with ETA note. Not a single line with a note. Correct?
(d) ETA note position — RESOLVED. Line level via QuoteLine.note (Riccardo #50, 2026-06-16).
(e) Stock-driven alternatives — RESOLVED. Standard pattern, not judgment call. Riccardo shipped #51 (2026-06-18): auto-pair available premium alternative when matched SKU is out of stock.
(f) Annotation source — RESOLVED. Manual. Agent composes the text; Odoo does not auto-generate. Written to QuoteLine.note field (Riccardo #50).
(g) Terrugem warehouse — does it affect delivery time? Odoo staging shows a custom field qty_available_terrugem on 2,195 products. Analysis suggests Terrugem stock IS already included in free_qty (not additive). Question: when stock is split between your main warehouse and Terrugem, does that change the ETA you write on the quote? If no difference, free_qty is correct and no change needed. Priority: Low.
Without these answers, v1 will either skip the alert entirely (silently quoting unavailable stock) or block too aggressively.
Priority: MEDIUM — re-elevated 2026-07-06. Downgraded to Low earlier the same day on "4 of 6 sub-questions already shipped" — but the Ayelen Montenegro call is live, current, first-hand evidence this exact pain point is unsolved for her today: "insufficient stock" shows as a bare warning, she must click into each product individually to see quantity + arrival date, and she explicitly wants the auto "need 80, have 40, rest arrives on [date]" behavior this item already proposes. The backend features shipped (#50, #51), but haven't reached her actual workflow yet.
Every Aronlight orçamento today carries 3 PT-tax-law-required elements that v1 must preserve when the agent writes back to Odoo (or generates a proposal directly). Example from Voltel OR 2026/13707:
1. ATCUD code (J6HF7M97-13707) — Código Único do Documento, mandatory per Portaria 195/2020. Format: 8-char issuer code + "-" + sequential doc number.
2. Software certification reference (PRZn- Processado por software certificado nº 2790/AT) — every fiscal doc must declare the certification number of the software that emitted it (Portaria 363/2010).
3. QR code containing ATCUD + invoice/quote summary — mandatory per Despacho 8632/2014.
· ATCUD is generated by Odoo automatically when a sale.order / invoice is created; the agent passes through, doesn't generate.
· The software certification number 2790/AT belongs to Odoo Portugal, not Aronlight specifically — it stays constant per Odoo instance.
· The QR code is rendered by Odoo's report template during PDF emission, not by upstream code.
(a) Confirm the agent only consumes ATCUD from Odoo (never generates).
(b) Is 2790/AT the certification number that should appear on every agent-generated proposal, or is there a different cert number for the Aronlight ES company (company_id=2)?
(c) If the agent ever generates a PDF without going through Odoo's sale.order workflow (e.g. an early draft for review), what fiscal elements can be present vs. must be omitted to stay compliant?
Priority: MEDIUM. Affects every quote, but Odoo likely auto-generates ATCUD/QR already per "What we believe" above, and GitHub has the corresponding issue (#52) at P3. Downgraded 2026-07-06 pending evidence of actual exposure.
list_price for the same SKU?
High
Cross-referencing 14 real proposals (190 SKU lines, June 2026) against Odoo catalog.json reveals a consistent pattern: the unit price shown on many proposals is significantly different from the Odoo list_price for the same SKU — even before any discount column is applied.
· Exact match (0%) — A.R.Costa, Voltel, Hipoloeste (luminaires), Sonepar accessories
· ~40% below Odoo list, disc1=0% — Reninstal (cases 36/37), DTE Hotel Quinta das Janelas (case 24). Discount is baked into the unit price; no discount column shown.
· ~55–60% below Odoo list, disc1=0% — Rodel / Marina Douro (case 41)
· ~25% above Odoo list — Electrostocks ES (case 35), coelca.com (case 25). Spain channel uses a higher base pricelist, then discounts 55–60%.
Full comparison: aronlight-price-comparison.pages.dev
(a) Does Aronlight maintain separate Odoo pricelists per client tier? Can you export — SUBSTANTIALLY ANSWERED, 2026-07-08. 44 unique pricelists confirmed, structure exported for 2 real examples (global % + per-SKU "líquido" fixed overrides). Not yet exhaustive across all 44. See product.pricelist + product.pricelist.item?docs/faq-answered.md § Pricelist & Partner discounts.
(b) For clients like Reninstal and Rodel, is the proposal always generated from a net pricelist (unit price already discounted, no disc% shown)? Or does it vary per quote?
(c) Spain markup (+25%): is this a separate ES pricelist with higher list prices, or a different base catalog in Odoo ES (company_id=2)?
(d) When the agent generates a quote, how does it know which pricelist to apply per client? Is this stored on res.partner in Odoo?
Priority: HIGH — the agent cannot generate correct quotes without knowing which pricelist to pull per client. This affects every line of every quote.
"Para esse cliente (DIFERENCIAL ELECTROTECNICA GERAL LDA) vejo: Lista PT 48% + Liquidos (EUR). E depois vejo preço 42 Euro. Entendo é líquido (mas achei IP65 no excel dos preços líquido). Poderia me explicar esse caso?"
Checked Odoo directly (2026-07-08): DIFERENCIAL ELECTROTECNICA GERAL LDA is confirmed on pricelist Lista PT 48% + Liquidos (EUR) (id 8026). That pricelist has exactly 47 rules: one global 48%-off-list rule, plus 46 named product-specific "líquido" overrides (fixed price, overriding the 48% math). We could not confirm whether the specific IP65 product Carla is looking at is among those 46 — she didn't cite a SKU — so this is open pending that detail.
(a) Which SKU is Carla looking at? Needed to check it directly against the 46-item override list on this pricelist.
(b) Is there a broader "líquidos" Excel master list (beyond what's loaded into this specific Odoo pricelist) that back office checks separately? If so, is Odoo supposed to be kept in sync with it, or does the Excel take precedence?
(c) If €42 is the correct price but isn't yet in Odoo's 46-item override list for this pricelist, should it be added — and is there a standing process for syncing newly-negotiated líquido prices into Odoo?
Priority: HIGH — same "which source wins" question as OD-4 and DISC-1, now surfacing at the level of a back-office person hitting a real, concrete discrepancy on a real client.
Comparing the RFQ agent's generated quote (Q-00148, DINOLUX INDUSTRIA E COMERCIO MATERIAL ELECTRICO SA, NIF 502281146, 09 Jul 2026) against Carla's own Odoo orçamento for the same order (OR 2026/15488, emitted 07 Jul 2026, Vendedor: Carla Santos) surfaces a third concrete example of the PRICE-2/PRICE-3 pattern — this time on one of Carla's own real quotes, not a question she raised.
What matches: every quantity agrees exactly across all lines. ILAR-00465 (both instances) match exactly at €2.98 — computed as list €5.73 × (1 − 48%) in both documents.
· ILAR-02137 (qty 25): system €30.77 vs Odoo €29.10 (+5.7%)
· ILAR-02137 (qty 1): system €30.77 vs Odoo €29.10 (+5.7%)
· ILAR-02441 (qty 37): system €34.67 vs Odoo €32.50 (+6.7%)
· ILAR-02135 (qty 17): system €22.28 vs Odoo €21.15 (+5.3%)
· ILAR-02135 (qty 11): system €22.28 vs Odoo €21.15 (+5.3%)
· ILAR-02072 (qty 11): system €30.33 vs Odoo €28.60 (+6.0%)
· ILAR-01198 (qty 58): system €19.50 vs Odoo €18.20 (+7.1%)
None reconcile to the same list × (1 − 48%) formula that correctly explains ILAR-00465 — e.g. ILAR-02137's system list price of €59.17 × 0.52 = €30.77 matches the system quote, but Carla's Odoo unit price of €29.10 isn't 48% off that same €59.17.
Also: 2 lines on the system-generated quote don't appear on Carla's Odoo orçamento at all — ILAR-02443 (qty 6, €276.24) and ILAR-00925 (qty 1, €16.12). Reconciliation: the 7 price deltas sum to +€249.78, the 2 missing lines add +€292.36 — together fully accounting for the pre-tax gap between the two documents (system €4,469.60 vs Odoo €3,927.45 = +€542.15). No unexplained residual.
(a) For the 7 mismatched lines, what price source did you use — a líquido override list (same shape as PRICE-3), a different pricelist than "Lista PT 48%," or a manually-typed net price?
(b) Were ILAR-02443 and ILAR-00925 deliberately left off this order, or should they have been included?
(c) Is your Odoo orçamento (OR 2026/15488) the price Dinolux should actually be charged, or is the system-generated quote closer to correct? We need to know which one is authoritative to fix the agent's pricing logic.
Priority: HIGH — same "which source wins" question as OD-4, PRICE-2, PRICE-3, and DISC-1, now with a third concrete example, reproducible against Carla's own live order rather than raised in the abstract.
1st Disc. vs 2nd Disc. semantics
Medium
Voltel OR 2026/13707 shows TWO discount columns on every line:
· 1st Disc. = 48 (= 48 %)
· 2nd Disc. = 0
PRICE-1 confirms 1st Disc. is the partner pricelist (Voltel = 48 % flat off list). What 2nd Disc. represents semantically is not yet confirmed.
Hyp A — 2nd Disc. is a per-order promo / negotiation discount applied on top of the pricelist (e.g. "Flávio gave Voltel an extra 5 % to close this week"). Filled in manually per quote.
Hyp B — 2nd Disc. is a per-line product-level discount (e.g. "campaign on the Nexa range, 10 % extra"). Filled in by Odoo automatically from a product.pricelist.item rule.
Hyp C — 2nd Disc. is a cascade from a parent pricelist (chained pricelist model: distributor pricelist references a project pricelist).
If C is right, the calculation is net = list × (1 − d1) × (1 − d2). If A or B, the agent only needs to consume the value from Odoo, not compute it.
The agent must preserve both fields in the generated quote even when 2nd Disc. is 0 — and must NOT compute 2nd Disc. itself (manual judgment or product-rule-driven, not derivable from partner alone).
Hyp A effectively confirmed for Spain (Adriana Fernandes call, 2026-07-06): she described exactly this pattern — a salesperson grants an ad hoc extra discount on specific line items (e.g. client's standard 60% plus 2% extra on 3 items), which Odoo has no structural way to capture — she corrects it manually at invoicing every time. Matches Hyp A: a manual, per-order, salesperson-driven addition, not a product rule or pricelist cascade.
Does NOT generalize to Italy (Ayelen Montenegro call, 2026-07-07): for Italian clients, the second discount is a fixed, known value per client profile (typically 20%, sometimes 10%), not a per-order negotiation — closer to Hyp B in spirit, but not yet captured as a product rule either. A working combined pricelist ("ITALIA 50+20%") already exists in Odoo but is assigned to zero customers — the fix is assignment, not construction. See aronlight#398.
Net finding: 2nd Disc. semantics are market-specific, not universal. Spain = ad hoc negotiation (Hyp A). Italy = fixed-per-client, mechanically solvable, just not wired up. Still needs Ricardo/Manel to confirm PT and France.
Doesn't block v1, but the data model needs both columns and the semantic determines whether the agent ever fills 2nd Disc. vs always reads it from Odoo.
Voltel OR 2026/13707 shows Validade: 15-07-2026 — exactly 30 days after emission (2026-06-15). Hipoloeste OR 2026/13737 (case 21) also shows a 30-day validity.
Every agent-generated quote uses emission_date + 30 days as validity, unless the partner record has a custom payment_term_id or quote-validity override in Odoo.
(a) Is 30 days the standard everywhere (PT + ES), or different per company?
(b) Do specific partners get extended validity by negotiation (60 days, 90 days, "open-ended")? If so, where is it stored in Odoo?
(c) What should happen if a customer accepts a quote AFTER its validity expires — auto-regenerate with current prices, or honor the original quote but flag for back-office review?
Sensible default works for v1; refinement is v2.
The PT Voltel quote shows IVA 23 % (Portugal mainland rate). Aronlight ES (company_id=2) operates in Spain, where standard VAT is IVA 21 % peninsular, with exceptions for Canarias (7 % IGIC) and Ceuta / Melilla (no VAT).
The agent reads account.tax linked to the sale.order via product.taxes_id per line, per company. Never hardcodes.
(a) Is the per-product, per-company tax wiring fully populated in Odoo today, or are there products where tax must be inferred from the buyer's region?
(b) For B2B distributor sales, is reverse-charge VAT ever applied (i.e. IVA 0 % with note "Sujeição passiva — invertido")? What triggers it?
Sensible default (read from Odoo) is correct; refinement when the ES company sees real traffic.
ILAR-02135 (Armadura TITAN 1200 IP65 36W 3CCT Prep. EM/Sensor) and ILAR-02137 (Armadura TITAN 1500 IP65 48W 3CCT) are currently in Odoo category "Armaduras Industriais", mapped to our INDUSTRIAL search bucket.
When a customer provides the SKU directly, we find them. When a customer describes the product by spec ("armadura IP65 36W emergência"), the agent's category pre-filter excludes them before the vector search runs — they are invisible. Both were MISS in eval cases #35 and #44.
Note: "Prep. EM/Sensor" in the product name means prepared for emergency/sensor (knockout holes for optional modules) — not that the product is a sensor. The Odoo category "Armaduras Industriais" may be correct; the question is whether it matches the full scope of use.
- (a) Are TITAN armaduras exclusively quoted in industrial projects (factories, warehouses), or do they also appear in mixed-use projects (garages in residential buildings, commercial warehouses, parking structures)?
- (b) If they appear outside pure industrial contexts, should they move to a different Odoo category — or is the fix on our side (widen code to also search INDUSTRIAL when an IP65 armadura is requested)?
Priority: MEDIUM — determines whether the fix is in Odoo or in code.
Infraestrutura de Portugal 2-lot public tender. Contact: pedro.moreira@pedromoreiraecia.pt (Bruno Lacerda). Please resend as direct attachment.
Huelva building. Contact: david.huarte@macinfor.com (David Huarte). Please resend as direct attachment.
7 of 8 items unidentifiable without the spec document. Originally from Tiago Vaz (tiagovaz@l3w.pt), forwarded to Alexandre Videira. Please resend.
When is a new orcamento created vs. the existing one revised? AlpLuz has three with identical quantities: OR 2026/5710, 7864, 7866.
- 3-3 — How often do RFQs arrive via WeTransfer/TransferNow rather than direct attachment?
- 3-4 — Abbreviated brand codes in cadernos: "OH SCUBA", "OHB BUC BEAM", "OH POD R" — mapping table?
- 3-5 — Functional labels "Tipo F", "Tipo G" — internal product category mapping?
- 3-6 — How often do requests arrive in Spanish Excel medicion format?
- 3-7 — Is Odoo staging a complete copy of production or partial?
- 3-8 — Should the agent search clients across both PT (company_id=3) and ES (company_id=2), or restrict by country?