HOCO B2B
DesignScreen specificationsBack-office

CRM

Page specs BO-09 to BO-15: resellers and prospects list and map, reseller 360°, create and edit form, validation queue, follow-ups and segments.

The CRM pages cover the commercial life of a point of sale, from prospect (prospect) to active reseller (revendeur actif) (cahier §4.2). Its ten lifecycle statuses are in ResellerStatus. Every record also carries a customer type (CustomerType: Super-gros, Demi-gros, Détail). The reseller declares it at sign-up, the back-office confirms it at validation, and only the back-office changes it afterwards, with an audit trail (AUTH-11). The customer type selects which of the three variant prices the reseller pays (PRC-02).

IDScreenSectionTemplateReleaseDesignBuild
BO-09Resellers & prospects listCRMbespokeV1Day 16DSH-03
BO-10Resellers mapCRMbespokeV1Day 16DSH-03
BO-11Reseller 360°CRMbespokeV1Day 16DSH-03
BO-12Reseller create / editCRMtemplateV1Day 16DSH-03
BO-13Account validation queueCRMbespokeV1Day 16DSH-03
BO-14Follow-ups & tasksCRMtemplateV1Day 16DSH-03
BO-15SegmentsCRMtemplateV1Day 16DSH-03

BO-09 — Resellers & prospects list

FieldValue
TemplateBespoke (List skeleton, with a map toggle)
ReleaseV1
Design dayDay 16 — DES-16
Build taskDSH-03
Route/crm/resellers
RequirementsCRM-11 · CRM-06 · CRM-05 · ANA-05
Permissions requiredcrm.view (page) · crm.create (« Nouveau revendeur ») · crm.update (bulk actions, status, assignment) · crm.export (export) · orders.view (revenue column) · field.view (last-visit column)

Purpose. Find any point of sale, prospect or reseller, filter the network by lifecycle, geography, delegate, segment, potential and activity, and act on it in bulk (cahier §4.2, §4.1 filters).

Who uses it. Commercial admin daily. Super admin and direction read it. The finance manager reads it to find a reseller.

Entry points.

  • CRM › Revendeurs.
  • Global search « Voir tous les résultats ».
  • Clicks from the reseller cards of BO-04.
  • The delegate detail (BO-17) with delegate= set.

Layout.

  • Header: « Revendeurs et prospects » with the count. The primary action is « Nouveau revendeur » (BO-12). « Exporter » sits next to it, and a Liste / Carte switch leads to BO-10 with the same filters.
  • View tabs (view):
    • « Tous »;
    • « Prospects » (NEW_PROSPECT, TO_CONTACT, INTERESTED);
    • « En activation » (APP_INSTALLED, ACCOUNT_CREATED, FIRST_ORDER);
    • « Actifs » (ACTIVE);
    • « À relancer » (TO_FOLLOW_UP);
    • « Non intéressés » (NOT_INTERESTED);
    • « Suspendus » (SUSPENDED).
  • Table:
ColumnSource fieldSortableDefault visible
N°number (REV-000123, mono)YesYes
MagasinstoreName + façade thumbnailYesYes
ResponsableownerNameYesYes
Téléphonephone (national display, click to call)NoYes
Type de clientcustomerType (pill)YesYes
WilayawilayaNameYesYes
CommunecommuneNameYesYes
Statutstatus (ResellerStatus pill)YesYes
CompteaccountStatus (AccountStatus pill; « — » for a prospect without an account)YesYes
DéléguéassignedDelegate.displayNameYesYes
Dernière commandelastOrderAtYesYes
Zonezone.nameYesNo
Segmentssegments[].name (chips, at most 2 + « +1 »)NoNo
PotentielpotentialYesNo
Type de commercebusinessType (BUSINESS_TYPE label)YesNo
Sourcesource (ResellerSource)YesNo
CA 90 joursrevenue90d (net HT, same basis as BO-04; needs orders.view)YesNo
Dernière visitelastVisitAt (needs field.view)YesNo
Tâches ouvertesopenTasksCountYesNo
Créé lecreatedAtYesNo
FilterControlURL parameter
Search (name, number, phone, owner)Textq
StatutMulti-select (preset by the tab)status
CompteMulti-select of AccountStatusaccountStatus
Type de clientMulti-select of CustomerTypecustomerType
Wilaya, CommuneSearchable selects (commune depends on wilaya)wilaya, commune
ZoneSelectzone
DéléguéSelect, including « Non assigné »delegate (none for unassigned)
SegmentMulti-selectsegment
PotentielMulti-select of Potentialpotential
Type de commerceMulti-selectbusinessType
SourceMulti-selectsource
ActivitéSelect: « Actif (60 j) », « Inactif », « Jamais commandé »activity = active / inactive / never
ValidationSelect of ValidationStatusvalidation
Créé entre / Validé entreDate rangescreatedFrom, createdTo, approvedFrom, approvedTo
Position GPS« Avec » / « Sans »hasGps
  • Default sort: createdAt descending. The « Actifs » tab sorts by lastOrderAt descending instead.
  • Bulk actions:
Bulk actionEndpointInput
« Assigner un délégué »admin.resellers.bulk (action: ASSIGN)Delegate and zone (the zone defaults to the commune's zone)
« Changer le statut »admin.resellers.bulk (action: STATUS)Target status (manual statuses only) and a reason
« Ajouter à un segment » / « Retirer du segment »admin.resellers.bulk (action: TAG)Segment
« Planifier une visite »—Opens BO-22 with the selection preselected as stops (?stops=…, at most 40)
« Exporter la sélection »admin.resellers.exportFormat
  • Row actions: « Ouvrir la fiche », « Modifier », « Appeler », « WhatsApp », « Créer une tâche », « Changer le statut ».
  • Export: XLSX or CSV of the current filters and visible columns.

Data.

Actions. Bulk assignment and tagging run through one call each, report per-record results and are not optimistic. Their confirmation reads « Assigner 24 revendeurs à Yacine M. (zone Oran Est) ? Les tournées déjà planifiées ne sont pas modifiées. ». A bulk status change requires a reason and writes one STATUS_CHANGE audit entry per reseller. A reassignment notifies the new delegate (push « 24 points de vente vous ont été attribués »).

Rules.

  • Statuses in bulk: only the manual statuses (TO_CONTACT, INTERESTED, NOT_INTERESTED, TO_FOLLOW_UP, SUSPENDED) can be set. APP_INSTALLED, ACCOUNT_CREATED, FIRST_ORDER and ACTIVE are set by events only (CRM-04).
  • Assignment keeps its history: ResellerAssignment rows are visible in the 360° (CRM-05).
  • Exports: every export is audited (EXPORT) with its filters, because it contains personal data (AUD-01).

Real-time. account.pending shows the banner « 1 nouveau compte en attente de validation » with a link to BO-13. The list itself refreshes only on demand, so rows never jump under the cursor.

States.

  • First use: « Aucun revendeur pour l'instant », with « Nouveau revendeur » and « Importer » (BO-67).
  • No results: reset link.
  • Hidden columns: without orders.view or field.view, the revenue and last-visit columns are absent from the column menu.

Acceptance criteria.

  • Filtering on wilaya 31, the « Prospects » tab and « Non assigné » returns exactly the unassigned prospects of Oran, and the URL reproduces the view when shared.
  • Searching 0555123456 finds the reseller whose phone is +213555123456.
  • Bulk-assigning 24 records produces 24 ResellerAssignment rows and one notification to the delegate.
  • The status menu offers no automatic status.
  • An export of 3 000 rows completes in the export centre, and the activity log shows an EXPORT entry with the filters.

BO-10 — Resellers map

FieldValue
TemplateBespoke
ReleaseV1
Design dayDay 16 — DES-16
Build taskDSH-03
Route/crm/resellers/map (same filter parameters as BO-09, plus bbox and zoom)
RequirementsCRM-11 · INT-01 · GEO-01
Permissions requiredcrm.view · crm.update (bulk actions on a lasso selection)

Purpose. See the network on a map: density by commune, uncovered areas, prospects near active resellers. Select points of sale geographically for assignment or a tour.

Who uses it. Commercial admin (zoning, tour preparation), direction.

Entry points. The Carte switch on BO-09, and « Voir sur la carte » in the 360° (BO-11).

Layout.

  • Map: full width, with the BO-09 filter bar on top.
  • Pins and clusters:
    • Pins are coloured by ResellerStatus tone and shaped by customer type (circle Détail, square Demi-gros, diamond Super-gros).
    • Clusters show counts above the server threshold.
  • Legend at the bottom left, with the count per status in the current view.
  • Missing GPS: the chip « 37 sans position GPS » links to BO-09 ?hasGps=false.
  • Pin popover: store name, number, status and type pills, delegate, last order, last visit. Actions: « Ouvrir la fiche », « Ajouter à une tournée », « Appeler ».
  • Lasso tool (polygon select): its sticky bar offers « 18 sélectionnés : Assigner · Ajouter au segment · Planifier une visite ».
  • Layer toggle « Zones »: highlights the pins of the selected zone and greys the others.

Data. admin.resellers.map with bbox, zoom and the BO-09 filters. It returns pins, or clusters { lat, lng, count } above the threshold, and is refetched on pan and zoom (debounced 300 ms). Bulk actions call admin.resellers.bulk.

Actions. Same bulk actions and confirmations as BO-09. « Ajouter à une tournée » asks for the delegate and date, then opens BO-22 with the stop added.

Rules.

  • Coordinates come from the record's GPS: captured by the delegate, set in BO-12, or geocoded when the maps provider allows it (GEO-04).
  • The lasso selects at most 200 pins. Beyond that: « Sélection limitée à 200 points — zoomez ».

Real-time. None.

States. Map provider failure shows « Carte indisponible — utilisez la liste » with the switch back. A filter with no geolocated result shows « Aucun point géolocalisé pour ces filtres ».

Acceptance criteria.

  • The status legend counts match BO-09 with the same filters and hasGps=true.
  • Zooming in splits clusters into pins without losing any record.
  • A lasso of 18 pins followed by « Assigner » assigns exactly those 18.

BO-11 — Reseller 360°

FieldValue
TemplateBespoke (Detail skeleton)
ReleaseV1
Design dayDay 16 — DES-16
Build taskDSH-03
Route/crm/resellers/[resellerId] (?tab=)
RequirementsCRM-12 · CRM-07 · CRM-04 · CRM-05 · CRM-10 · AUTH-11
Permissions requiredcrm.view (page) · crm.update (edit, status, customer type, assignment, notes, documents) · crm.validate (validation shortcut) · orders.view (Commandes tab, KPIs) · orders.create (« Nouvelle commande ») · finance.view (Finance tab, balance and credit) · field.view (Visites tab) · support.view (Tickets et SAV tab)

Purpose. One page that tells everything about a point of sale (cahier §4.2): identity and contacts, location, lifecycle and customer type, assigned delegate, orders, invoices, payments, credit, visits and reports, tasks, interactions, tickets and after-sales claims, returns, documents and the invitation funnel.

Who uses it. The commercial admin before a call or a decision. The finance manager for credit questions. Direction to understand a key account.

Entry points.

  • BO-09 and BO-10 rows and pins.
  • Global search.
  • Links from orders (BO-39), visits (BO-25), tickets (BO-56), the validation queue (BO-13) and the finance pages.

Header

  • Identity line: façade photo (64 px), store name, REV-000123 (copy on click).
    • Pills: ResellerStatus, AccountStatus when an account exists, ValidationStatus while pending, and customer type (CustomerType, brand tone).
  • Facts row:
    • Owner name and contact role (PERSON_ROLE).
    • Phone (click to call) and WhatsApp (wa.me).
    • Wilaya and commune. The support region from BO-70 shows in a tooltip.
    • Assigned delegate (link to BO-17) and zone.
    • Source and creating delegate.
    • Segments and potential.
    • « Client depuis » (the approval date).
  • KPI strip (each card needs its permission):
    • CA 12 mois (net HT).
    • Commandes (12 months).
    • Panier moyen.
    • Dernière commande (date, plus days since).
    • Solde dû (TTC; finance.view).
    • Crédit disponible (limit − used; finance.view).
    • Dernière visite (field.view).
  • Primary action, chosen by state:
    • « Valider le compte », when validation is PENDING and the user has crm.validate: opens the BO-13 decision panel for this record.
    • Otherwise « Nouvelle commande » (BO-40, with orders.create). It is disabled with a tooltip when the account is not active or the reseller is SUSPENDED.
  • « Plus » menu: « Modifier » (BO-12), « Changer le statut », « Changer le type de client », « Assigner », « Ajouter une note / un appel », « Créer une tâche », « Planifier une visite », « Voir sur la carte », « Suspendre » or « Réactiver ».

Tabs

Tab (tab)ContentDataNeeds
Aperçu (overview, default)Left: contacts, delivery addresses (default marked), mini-map with the pin and GPS accuracy, photos strip, business type, potential, notes. Right: the five latest interactions, open tasks (with due dates, overdue in red), the latest visit with its interest level and next action.admin.resellers.getcrm.view
Commandes (orders)Orders table (number, date, channel, status, total TTC, first-order badge), filters by status and period. A row opens BO-39.admin.orders.list ?reseller=orders.view
Finance (finance)Credit card (limit, used, available, blocked flag, limit history), invoices (number, date, due date, TTC, balance, status), payments and declarations (number, method, amount, status, allocation), credit notes.admin.credit.get, admin.invoices.list, admin.payments.list ?reseller=finance.view
Visites (visits)Visits table (number, date, delegate, type, status, check-in distance, duration, interest level, next action). A row opens BO-25. Visit reports are summarised inline: person met, products and promotions presented, issues.admin.visits.list ?reseller=field.view
Tâches (tasks)Follow-ups for this reseller: open first, then done; « Créer une tâche ».admin.tasks.list ?reseller=crm.view
Historique (timeline)Unified timeline (CRM-07): calls, visits, notes, WhatsApp, SMS, email, orders, payments, claims, status changes, customer-type changes, assignments, newest first. Filter chips per InteractionType. Each entry shows the actor, the time and a link to its record. « Ajouter une note » sits on top.admin.resellers.timelinecrm.view
Tickets et SAV (support)Tickets, after-sales claims first (type, related order, status, resolution), and return requests (RET-…, status, credit note).admin.tickets.list ?reseller=, admin.returns.list ?reseller=support.view; returns need orders.view
Documents (documents)Documents (DocumentType: RC, NIF, NIS, AI, ID, contract) and photos (PhotoKind) with upload date, uploader and expiry when relevant. « Ajouter ». Files open through signed URLs.admin.resellers.documents, admin.resellers.documents.add, files.downloadUrlcrm.view; adding needs crm.update
Activation (activation)The invitation funnel (InvitationStep, each step dated): sent → app installed → account created → phone verified → catalog viewed → first order, with the inviting delegate and channel.admin.invitations.list ?reseller=field.view

Tab labels carry the counters returned by admin.resellers.get (« Commandes 18 », « Tâches 2 »). A tab whose permission is missing is not rendered.

Data.

Actions

ActionEndpointConfirmation (FR)ReasonOptimisticAuditNotifies
« Changer le statut »admin.resellers.setStatus« Passer Boutique Nour de Intéressé à Non intéressé ? »Required, free textNoSTATUS_CHANGE (from → to, reason)Assigned delegate (in-app)
« Suspendre »admin.resellers.setStatus (SUSPENDED)« Suspendre Boutique Nour ? Le revendeur ne pourra plus commander ; ses commandes en cours ne sont pas annulées. »RequiredNoSTATUS_CHANGEReseller (SMS + push « Votre compte est suspendu, contactez HOCO ») and delegate
« Changer le type de client »admin.resellers.update (customerType)« Passer Boutique Nour de Détail à Demi-gros ? Les prix Demi-gros s'appliqueront aux prochains paniers ; les commandes déjà passées ne changent pas. »RequiredNoUPDATE (customerType before → after, reason)Reseller (push + in-app « Vos conditions tarifaires ont été mises à jour »)
« Assigner »admin.resellers.assign« Assigner à Yacine M. (zone Oran Est) ? »OptionalNoUPDATE + ResellerAssignment rowNew and previous delegate
« Ajouter une note / un appel »admin.resellers.notes.add——Yes: appears at once in Historique, rolled back on errorCREATE (interaction)—
« Créer une tâche »admin.tasks.create— (drawer, see BO-14)—NoCREATEAssignee
« Planifier une visite »—Asks for delegate and date, then opens BO-22 with the stop————
« Ajouter un document »files.createUpload → files.completeUpload → admin.resellers.documents.add——NoCREATE—

Rules

  • Customer type (AUTH-11, PRC-02):
    • It drives the price: the reseller pays the variant's priceSuperGros, priceDemiGros or priceDetail, then promotions.
    • A change applies to carts re-priced after the change. Submitted orders keep their prices.
    • Changing it is a back-office action only, always audited with a reason.
  • Statuses: the status menu offers only the manual transitions of the reseller lifecycle (CRM-04). Automatic statuses come from events: install, account creation, first order, activity window.
  • Suspension blocks new orders (checkout answers 403) without touching orders already submitted.
  • Purchase prices and margins never appear on this page (ACL-04). Finance figures need finance.view.
  • Documents and photos are private files read through 5-minute signed URLs (SEC-04).
  • Concurrency: header edits send version. A 409 VERSION_CONFLICT opens the standard reload dialog.

Real-time.

  • order.created and order.status_changed for this reseller refresh the KPI strip and the Commandes tab, debounced 10 s.
  • visit.completed for this reseller refreshes Visites and Aperçu.

States.

  • Prospect without an account: no Finance tab, the KPIs show « — », and the primary action is « Planifier une visite ».
  • Rejected validation: a banner shows the rejection reason and date.
  • Restricted tabs: a tab whose permission is missing is not rendered; deep links to it fall back to Aperçu.
  • Archived or merged record (V2 merge, CRM-13): read-only banner.
  • Not found or out of scope: the « Introuvable » page.

Acceptance criteria

  • The page shows orders, invoices, payments, visits, reports, tasks and interactions of the reseller in one place (CRM-12). Each tab's count matches its list.
  • Changing the customer type from Détail to Demi-gros writes an UPDATE audit entry with both values and the reason. The reseller's next cart shows Demi-gros prices; an order already submitted keeps its prices.
  • A finance manager sees the Finance tab. A commercial admin without finance.view sees neither the tab nor the balance and credit cards, and the API response contains no finance fields.
  • Suspending the reseller makes the next checkout from the reseller app fail with the suspension message. The timeline shows the status change with its reason.
  • A note added here appears in the delegate app's point-of-sale sheet after its next sync.
  • The Activation tab shows each invitation step with its date, matching the delegate app (IVT-03).

BO-12 — Reseller create / edit

FieldValue
TemplateForm
ReleaseV1
Design dayDay 16 — DES-16
Build taskDSH-03
Route/crm/resellers/new · /crm/resellers/[resellerId]/edit
RequirementsCRM-01 · CRM-02 · CRM-03 · AUTH-11 · CRM-10 · GEO-01
Permissions requiredcrm.create (new) · crm.update (edit)

Purpose. Create a prospect or reseller from the back-office, for example after a phone call (source BACK_OFFICE), or correct a record. The minimum data set of cahier §15.5 is enforced, and the phone is unique.

Who uses it. Commercial admin, super admin.

Entry points. « Nouveau revendeur » on BO-09, and « Modifier » on BO-11.

Layout. A page form with four sections and the sticky save bar. Duplicate hints show inline under the phone field.

SectionFieldTypeValidationDefaultHelp text / permission
MagasinNom du magasinTextRequired, 2–120 characters——
Type de commerceSelect (BUSINESS_TYPE)Required——
Type de clientThree radio cards (CustomerType) with one line each: « Gros volumes, prix le plus bas », « Volumes intermédiaires », « Boutique de détail »RequiredNone. The user must choose.« Détermine lequel des trois prix s'applique au revendeur. » In edit mode, see the rule below.
PotentielSegmented control (Potential)OptionalMEDIUM—
ContactResponsableTextRequired, 2–80 characters——
FonctionSelect (PERSON_ROLE)Optional« Gérant »—
Téléphone principalPhone (national or E.164)Required, valid Algerian mobile or landline, unique after normalisation—Live duplicate check (see Rules). Read-only once the reseller has an account.
WhatsAppPhone + « Identique au téléphone » checkboxOptional, validCheckbox ticked—
EmailEmailOptional, valid——
AdresseWilayaSearchable selectRequired——
CommuneSearchable select, filtered by wilayaRequired——
AdresseTextRequired, 5–200 characters——
RepèreTextOptional, 120 characters max—« Ex. : en face de la poste »
Position GPSMap picker (drag the pin) + « Géolocaliser l'adresse »Optional; lat/lng inside AlgeriaGeocoded from the commune centroid« Indispensable pour les tournées »
AffectationDéléguéSelect of delegates whose zones contain the communeOptional—Warning when the delegate's zones do not contain the commune
ZoneSelectOptionalThe commune's zone—
SegmentsMulti-selectOptional——
Statut initialSelect: NEW_PROSPECT, TO_CONTACT, INTERESTED (create only)RequiredNEW_PROSPECT—
PiècesDocumentsUploader per DocumentType (PDF/JPEG/PNG, 10 MB max)Optional—Private files
PhotosUploader per PhotoKind (JPEG/PNG/WebP, 5 MB max)Optional—The façade photo is recommended

Data.

Actions.

ActionEndpointBehaviourAudit
« Créer le revendeur »admin.resellers.createSource BACK_OFFICE, REV- number assigned by the server, then BO-11 opensCREATE
« Enregistrer » (edit)admin.resellers.updateBack to BO-11 with the toast « Fiche mise à jour »UPDATE with the changed fields
Change of customer type in edit modeadmin.resellers.updateConfirmation « Passer de Détail à Demi-gros ? Les prix Demi-gros s'appliqueront aux prochains paniers. » and a required reasonUPDATE (customerType before → after); reseller notified

Rules.

  • Duplicates (CRM-03):
    • When the phone already exists, an inline card shows « Ce numéro appartient déjà à REV-000123 — Boutique Nour (Oran, Revendeur actif) » with « Ouvrir la fiche ». Creation is blocked.
    • The server answers 409 PHONE_ALREADY_EXISTS if the check is bypassed.
  • Phone of an account holder: read-only, with the hint « Le revendeur modifie son numéro depuis l'application (vérification par SMS) » (OtpPurpose.PHONE_CHANGE).
  • Customer type (AUTH-11):
    • It is required at creation.
    • For a reseller whose account is not yet validated, the type stays editable without a reason; validation confirms it (BO-13).
    • After validation, any change requires a reason and is audited.
  • Status is not edited here after creation; « Changer le statut » on BO-11 does it.
  • Unsaved changes are guarded. A 409 VERSION_CONFLICT shows the reload dialog.

Real-time. None.

States.

  • The duplicate check shows a spinner beside the field while running.
  • Upload progress and errors are shown per file.
  • With a delegate outside the commune's zones: the warning « Ce délégué ne couvre pas cette commune » (saving stays possible).

Acceptance criteria.

  • Entering an existing phone, in any format, shows the duplicate card and disables « Créer ».
  • Saving without a customer type is refused with « Choisissez un type de client ».
  • Editing the customer type of a validated reseller asks for a reason and adds an UPDATE audit entry.
  • A record created here appears in BO-09 with source Back-office, and in the delegate app of the assigned delegate after sync.

BO-13 — Account validation queue

FieldValue
TemplateBespoke (List skeleton, master-detail)
ReleaseV1
Design dayDay 16 — DES-16
Build taskDSH-03
Route/crm/validation (?id= for the selected record)
RequirementsCRM-09 · FLD-14 · AUTH-11 · CRM-03 · AUTH-05
Permissions requiredcrm.validate (page and decisions) · crm.update (edits made from the panel)

Purpose. Approve or reject new reseller accounts (self sign-up, claims of field prospects) and new points of sale created by delegates (cahier §4.2 « La validation du compte est réalisée par un utilisateur autorisé », §4.5 « Validation des nouveaux points de vente »). Before an account is approved, the reviewer confirms or changes the declared customer type and checks the duplicate hints.

Who uses it. Commercial admin, several times a day. The super admin.

Entry points.

  • CRM › Comptes à valider (badge).
  • The account.pending toast.
  • The « À traiter » panel on BO-04.
  • « Valider le compte » on BO-11.

Layout

  • Tabs:
    • « Tous ».
    • « Comptes revendeurs »: self sign-ups and claims, AccountStatus = PENDING_VALIDATION.
    • « Nouveaux points de vente »: field creations by delegates, ValidationStatus = PENDING without an account.
    • « Doublons probables »: items with at least one strong hint.
  • Left column, the queue (oldest first, 400 px):
    • Each item shows the store name, commune and wilaya, the source (ResellerSource icon), the creating delegate or « Inscription revendeur », and the waiting time.
    • Waiting time turns amber after 24 h and red after 48 h. Assumption — the SLA is to confirm with HOCO.
    • Badges: declared customer type, duplicate-hint count (danger tone when strong), and completeness (« 4/6 pièces »).
  • Right panel, the decision for the selected item:
    1. Identity: store, owner, phone (with « vérifié par SMS » when the OTP was passed), WhatsApp, email, business type, potential, address, map with the pin and accuracy.
    2. Customer type to confirm:
      • The declared value is highlighted (« Déclaré à l'inscription : Demi-gros »).
      • Three radio cards preselect the declared value, each showing an example price of a reference product (« Câble X14 : 245,00 DA HT »).
      • Hints to help decide: business type, store photos, the delegate's note, and the potential set by the delegate.
    3. Duplicate hints (see below), each with a side-by-side comparison.
    4. Documents and photos: thumbnails that open in a viewer (zoom, rotate). A missing recommended piece is listed (« Photo de façade manquante »).
    5. Origin: source, creating delegate and visit (link to BO-25), invitation code used, sign-up time.
    6. Assignment at approval: delegate and zone, preset from the commune and the creating delegate.
    7. Decision bar (sticky): « Valider le compte » (primary) and « Refuser » (danger, outline).
  • Keyboard:
    • J / K: next or previous item.
    • 1 / 2 / 3: customer type Super-gros / Demi-gros / Détail.
    • A: approve (opens the confirmation).
    • R: refuse.
    • D: open the first duplicate.

Duplicate hints

Returned by admin.resellers.validation.list for each item, strongest first:

HintRuleStrength
Same main phoneImpossible by construction: a phone match triggers the claim flow (AUTH-05). Listed for completeness.—
WhatsApp or secondary phone = another record's main phoneExact match after normalisationStrong
Same GPS spotAnother point of sale within 50 mStrong when the store name is also similar, else medium
Similar store name in the same communeTrigram similarity of at least 0.6Medium
Same RC or NIF numberFrom uploaded documents, when capturedStrong
Same emailCase-insensitiveMedium

Each hint card shows the other record (number, name, status, delegate, last order) with its matched fields highlighted. It offers « Comparer » (two-column diff), « Ce n'est pas un doublon » (dismisses the hint for this pair), and « Refuser comme doublon de REV-000123 » (prefills the rejection reason). Merging records is V2 (CRM-13).

Data.

Actions

ActionEndpointConfirmation (FR)ReasonOptimisticAuditNotifies
« Valider le compte »admin.resellers.validate (APPROVE, customerType)« Valider Boutique Nour comme client Demi-gros ? Le revendeur pourra commander aux prix Demi-gros. » When the type differs from the declared one: « Le type déclaré était Détail » plus a required reason.Required only when the type is changedNo; the item leaves the queue after the responseVALIDATE; plus UPDATE of customerType when changedReseller: SMS + push « Votre compte HOCO est validé ». Creating delegate: in-app.
« Refuser »admin.resellers.validate (REJECT)« Refuser ce compte ? Le motif sera communiqué au revendeur. »Required, free text of at least 10 characters (chips: « Doublon de REV-… », « Informations incomplètes », « Hors zone de distribution »)NoREJECTReseller (SMS + push with the reason); delegate (in-app)
« Ce n'est pas un doublon »admin.resellers.update (dismissed hint)——YesUPDATE—
Quick fix of a field (address, business type)admin.resellers.update——NoUPDATE—

Rules

  • Who decides: only holders of crm.validate (CRM-09).
  • Customer type (AUTH-11):
    • Approval always records a confirmed customer type. The request carries customerType even when unchanged.
    • Approval with a type different from the declared one needs a reason. Both values stay in the history.
  • What approval does:
    • It sets ValidationStatus = APPROVED and, for an account, AccountStatus PENDING_VALIDATION → ACTIVE, so the reseller can now order.
    • A rejected account stays PENDING_VALIDATION with ValidationStatus = REJECTED. The reseller app shows the reason (RA-06).
    • A rejected field point of sale is kept with REJECTED and hidden from BO-09's default views.
  • Customer type before validation: after sign-up, a reseller sees the prices of their declared type before validation, but cannot order until approved (AUTH-10; decision to confirm in open decisions).
  • Concurrency: two reviewers cannot both decide. The second gets 409 VERSION_CONFLICT with « Déjà traité par Karim B. à 10:42 », and the item disappears.

Real-time. account.pending prepends the new item to the queue, without moving the current selection, and increments the badge.

States.

  • Empty queue: « Aucun compte en attente. Tout est à jour. » (success tone).
  • Selected item already decided elsewhere: the panel shows « Ce compte a été traité par … », then moves to the next item.
  • Documents still uploading from the delegate's offline queue: « 2 photos en cours de synchronisation ».

Acceptance criteria

  • A self sign-up appears in the queue within 5 s of account creation, with its declared customer type (cahier §12 « Une inscription valide apparaît dans le back-office et peut être approuvée »).
  • Approving with the declared type sets the account ACTIVE, records customerType, and sends the validation SMS and push.
  • Approving with another type requires a reason and writes both VALIDATE and UPDATE audit entries.
  • Rejecting requires a reason of at least 10 characters. The reseller app then shows that reason.
  • A record whose WhatsApp number equals an existing reseller's phone shows a strong duplicate hint naming that reseller.
  • Keyboard-only processing (J, 2, A, Enter) approves an item as Demi-gros and selects the next one.

BO-14 — Follow-ups & tasks

FieldValue
TemplateList
ReleaseV1
Design dayDay 16 — DES-16
Build taskDSH-03
Route/crm/tasks
RequirementsCRM-08 · FLD-10
Permissions requiredcrm.view (page) · crm.update (create, reassign, reschedule, complete, cancel)

Purpose. Follow every follow-up (relance), task and next action across the team, whether it came from a visit report, an inactivity rule or a manual entry, with due dates (cahier §4.2 « Relances, tâches, prochaines actions et notifications »).

Who uses it. Commercial admin. Each staff user sees « Mes tâches ».

Entry points. CRM › Relances et tâches (badge = my overdue tasks), the Tâches tab of BO-11, and task notifications.

Layout.

  • Tabs:
    • « Mes tâches ».
    • « En retard »: derived, OPEN with dueAt in the past.
    • « Aujourd'hui ».
    • « À venir ».
    • « Terminées ».
    • « Toutes ».
  • Columns (all default visible except the last two):
ColumnSource fieldSortable
ÉchéancedueAt (red when overdue)Yes (default ascending)
Typetype (TaskType)Yes
Revendeurreseller.storeName + numberYes
Assignée àassignee.displayName (delegate or staff)Yes
Origineorigin (« Rapport de visite VIS-… », « Inactivité », « Manuel »)No
Statutstatus (TaskStatus) or « En retard »Yes
Notenote (first line)No
Résultatoutcome (done tasks)No
Créée lecreatedAtYes
  • Filters: assignee, type, status, dueFrom / dueTo, reseller, zone, origin.
  • Drawer « Nouvelle tâche »:
    • Revendeur (search, required).
    • Type (required).
    • Échéance (date + optional time, required, not in the past).
    • Assignée à (staff or delegate, required; defaults to the reseller's delegate).
    • Note (500 characters max).
  • Bulk actions: « Réassigner », « Replanifier ».
  • Row actions: « Terminer » (outcome, required, 300 characters max), « Replanifier », « Réassigner », « Annuler » (reason).

Data. admin.tasks.list, admin.tasks.create, admin.tasks.update.

Actions.

  • Create, reassign and reschedule are not optimistic. « Terminer » is optimistic (the row moves to « Terminées »).
  • Each action writes an audit entry (CREATE / UPDATE).
  • The assignee is notified on creation and reassignment: push for delegates, in-app for staff.

Rules.

  • « En retard » is derived and never stored (TaskStatus note).
  • A visit report with a next action other than NONE creates a task automatically, with origin « Rapport de visite » (FLD-10).
  • Tasks assigned to a delegate sync to the delegate app (DA-19).
  • Completing a task adds an entry to the reseller's timeline.

Real-time. None. The list refreshes on focus.

States. « Aucune tâche en retard » is a positive empty state. A reseller that is out of scope or deleted shows « Revendeur introuvable ».

Acceptance criteria.

  • A visit report with « Relance téléphonique » on 12/11 creates a task due on 12/11, assigned to the visiting delegate, visible here and in the delegate app.
  • At midnight in Algiers, an open task due yesterday appears under « En retard ».
  • Reassigning notifies the new assignee and writes an UPDATE audit entry.

BO-15 — Segments

FieldValue
TemplateList (with drawer)
ReleaseV1
Design dayDay 16 — DES-16
Build taskDSH-03
Route/crm/segments (?drawer=)
RequirementsCRM-06 · CAT-05 · PRM-02
Permissions requiredcrm.administer

Purpose. Maintain the reseller segments used for product visibility (CAT-05), promotion and banner targeting (PRM-02) and announcements. Examples: « Grands comptes Oran », « Boutiques téléphonie centre-ville ». Segmentation by potential, business type, brands sold and activity (cahier §4.2) is done with list filters, and the result is saved as a segment. Customer type is its own field, not a segment.

Who uses it. Commercial admin.

Entry points. CRM › Segments, and « Ajouter à un segment » in BO-09 and BO-10.

Layout.

  • Table: Nom, Description, Couleur, Revendeurs (count), Utilisé par (promotions, banners, visibility rules, announcements as chips with counts), Modifié le.
  • Drawer:
    • Nom: required, unique, 3–60 characters.
    • Description: 200 characters max.
    • Couleur: one of 8 swatches.
    • Membres: count, plus « Voir les membres », which opens BO-09 ?segment=.
    • « Ajouter par critères »: a one-shot add of all resellers matching potential, business type, wilaya or activity, with a preview count.

Data. admin.segments.crud. Members are added through admin.resellers.bulk (TAG).

Actions.

  • Create, rename: no confirmation; audited CREATE / UPDATE.
  • Delete: « Supprimer le segment Grands comptes Oran ? 42 revendeurs en sont membres. » When the segment is used by an active promotion, banner or visibility rule, deletion is refused (409) and lists the usages.
  • « Ajouter par critères »: « Ajouter 57 revendeurs au segment ? »

Rules.

  • Segments are static: membership changes only by explicit actions. « Ajouter par critères » is a one-time add, not a dynamic rule. Assumption — dynamic segments are not in V1.
  • A reseller can belong to several segments.

Real-time. None.

States. First use: « Créez un segment pour cibler vos promotions et votre catalogue. »

Acceptance criteria.

  • A segment used by an active promotion cannot be deleted, and the error names the promotion.
  • « Ajouter par critères » with Potentiel = Élevé and wilaya 16 adds exactly the resellers BO-09 returns for those filters.
  • Members added here show the segment chip in BO-09 and BO-11.

On this page