update
This commit is contained in:
parent
5a97745d42
commit
9578594628
13 changed files with 361 additions and 102 deletions
|
|
@ -9,6 +9,9 @@
|
|||
'data': [
|
||||
'views/itch_cycle_product_partner_view.xml',
|
||||
'views/res_partner_view.xml',
|
||||
'views/product_category_view.xml',
|
||||
'security/ir.model.access.csv'
|
||||
|
||||
],
|
||||
'installable': True,
|
||||
'application': False,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
|
||||
from . import itch_cycle_product_partner
|
||||
from . import sale_order
|
||||
from . import sale_order_line
|
||||
from . import product_category
|
||||
from . import res_partner
|
||||
|
|
|
|||
|
|
@ -1,33 +1,195 @@
|
|||
|
||||
from datetime import datetime, timedelta
|
||||
import numpy as np
|
||||
from odoo import models, fields, api
|
||||
from datetime import timedelta, datetime
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class ItchCycleProductPartner(models.Model):
|
||||
_name = 'itch_cycle_product_partner'
|
||||
_description = 'Itch Cycle by Product and Partner'
|
||||
_name = "itch.cycle.product.partner"
|
||||
_description = "Cycle Produit/Partenaire"
|
||||
|
||||
partner_id = fields.Many2one('res.partner', string="Client", required=True, ondelete='cascade')
|
||||
product_id = fields.Many2one('product.product', string="Produit", required=True)
|
||||
last_purchase_date = fields.Date(string="Dernière Date d'Achat")
|
||||
itch_cycle_duration = fields.Integer(string="Durée du Itch-Cycle (jours)", default=0)
|
||||
next_follow_up_date = fields.Date(string="Prochaine Date de Suivi", compute="_compute_next_follow_up_date", store=True)
|
||||
partner_id = fields.Many2one(
|
||||
comodel_name='res.partner',
|
||||
string="Client",
|
||||
required=True
|
||||
)
|
||||
|
||||
@api.depends('last_purchase_date', 'itch_cycle_duration')
|
||||
def _compute_next_follow_up_date(self):
|
||||
product_id = fields.Many2one(
|
||||
comodel_name='product.product',
|
||||
string="Produit",
|
||||
required=True
|
||||
)
|
||||
|
||||
average_cycle = fields.Integer(
|
||||
string="Cycle moyen (jours)",
|
||||
compute="_compute_average_cycle",
|
||||
store=True
|
||||
)
|
||||
|
||||
next_expected_date = fields.Date(
|
||||
string="Prochaine vente prévue",
|
||||
compute="_compute_next_expected_date",
|
||||
store=True
|
||||
)
|
||||
|
||||
prediction_status = fields.Selection(
|
||||
selection=[
|
||||
('on_time', 'À l’heure'),
|
||||
('delayed', 'Retardée')
|
||||
],
|
||||
string="Statut de la prédiction",
|
||||
compute="_compute_prediction_status"
|
||||
)
|
||||
|
||||
sale_order_line_ids = fields.One2many(
|
||||
comodel_name='sale.order.line',
|
||||
inverse_name='itch_cycle_id',
|
||||
string="Lignes de commande"
|
||||
)
|
||||
|
||||
next_follow_up_date = fields.Date(
|
||||
string="Prochaine date de suivi",
|
||||
compute="_compute_next_follow_up_date",
|
||||
store=True,
|
||||
readonly=False
|
||||
)
|
||||
|
||||
last_purchase_date = fields.Date(
|
||||
string="Date du dernier achat",
|
||||
compute="_compute_last_purchase_date",
|
||||
store=True
|
||||
)
|
||||
|
||||
itch_cycle_duration = fields.Integer(
|
||||
string="Durée du cycle (jours)",
|
||||
help="Représente la durée moyenne du cycle en jours",
|
||||
compute="_compute_itch_cycle_duration",
|
||||
store=True
|
||||
)
|
||||
|
||||
@api.depends('average_cycle')
|
||||
def _compute_itch_cycle_duration(self):
|
||||
"""Calcule automatiquement la durée du cycle."""
|
||||
for record in self:
|
||||
if record.last_purchase_date and record.itch_cycle_duration > 0:
|
||||
record.next_follow_up_date = record.last_purchase_date + timedelta(days=record.itch_cycle_duration)
|
||||
record.itch_cycle_duration = record.average_cycle or 0
|
||||
|
||||
@api.depends('sale_order_line_ids')
|
||||
def _compute_last_purchase_date(self):
|
||||
"""Met automatiquement à jour la date du dernier achat."""
|
||||
for record in self:
|
||||
# Rechercher la commande la plus récente associée
|
||||
last_order = record.sale_order_line_ids.mapped('order_id').sorted(key=lambda o: o.date_order, reverse=True)
|
||||
record.last_purchase_date = last_order[0].date_order if last_order else None
|
||||
|
||||
@api.depends('next_expected_date')
|
||||
def _compute_next_follow_up_date(self):
|
||||
"""
|
||||
Définit la logique pour calculer automatiquement la date de suivi.
|
||||
Peut être basée sur `next_expected_date`, mais modifiable par l'utilisateur.
|
||||
"""
|
||||
for record in self:
|
||||
if record.next_expected_date:
|
||||
# Exemple : une alerte de suivi une semaine avant la prochaine vente prévue
|
||||
record.next_follow_up_date = record.next_expected_date - timedelta(days=7)
|
||||
else:
|
||||
record.next_follow_up_date = False
|
||||
record.next_follow_up_date = None
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
@api.depends('sale_order_line_ids', 'product_id.categ_id')
|
||||
def _compute_average_cycle(self):
|
||||
for record in self:
|
||||
product_category = record.product_id.categ_id
|
||||
if product_category.seasonal_factor and product_category.season_months:
|
||||
# Filtrer les commandes par mois saisonniers de la catégorie
|
||||
active_months = list(map(int, product_category.season_months.split(',')))
|
||||
dates = sorted([
|
||||
line.order_id.date_order
|
||||
for line in record.sale_order_line_ids
|
||||
if line.order_id.date_order.month in active_months
|
||||
])
|
||||
else:
|
||||
# Cycle habituel (non saisonnier)
|
||||
dates = sorted(record.sale_order_line_ids.mapped('order_id.date_order'))
|
||||
|
||||
itch_cycle_product_ids = fields.One2many('itch_cycle_product_partner', 'partner_id', string="Itch Cycles Produits")
|
||||
itch_next_delay = fields.Date(string="Prochaine Date de Suivi (Itch-Cycle Min)", compute="_compute_itch_next_delay", store=True)
|
||||
if len(dates) > 1:
|
||||
intervals = [(dates[i + 1] - dates[i]).days for i in range(len(dates) - 1)]
|
||||
record.average_cycle = int(np.mean(intervals)) if intervals else 0
|
||||
else:
|
||||
record.average_cycle = 0
|
||||
|
||||
@api.depends('itch_cycle_product_ids.next_follow_up_date')
|
||||
def _compute_itch_next_delay(self):
|
||||
for partner in self:
|
||||
follow_up_dates = partner.itch_cycle_product_ids.mapped('next_follow_up_date')
|
||||
partner.itch_next_delay = min(follow_up_dates) if follow_up_dates else False
|
||||
@api.depends('average_cycle')
|
||||
def _compute_next_expected_date(self):
|
||||
for record in self:
|
||||
if record.average_cycle and record.sale_order_line_ids:
|
||||
last_date = max(record.sale_order_line_ids.mapped('order_id.date_order'))
|
||||
record.next_expected_date = fields.Date.from_string(last_date) + timedelta(days=record.average_cycle)
|
||||
else:
|
||||
record.next_expected_date = None
|
||||
|
||||
def _compute_prediction_status(self):
|
||||
today = fields.Date.context_today(self)
|
||||
for record in self:
|
||||
if record.next_expected_date and record.next_expected_date < today:
|
||||
record.prediction_status = 'delayed'
|
||||
else:
|
||||
record.prediction_status = 'on_time'
|
||||
|
||||
@api.model
|
||||
def populate_from_past_orders(self):
|
||||
"""
|
||||
Méthode pour traiter le passé :
|
||||
Crée des enregistrements 'itch.cycle.product.partner'
|
||||
basés sur les commandes de vente existantes.
|
||||
"""
|
||||
# Récupérer toutes les lignes de commandes confirmées
|
||||
sale_order_lines = self.env['sale.order.line'].search([
|
||||
('order_id.state', 'in', ['sale', 'done']) # Commandes confirmées ou terminées
|
||||
])
|
||||
|
||||
# Carte pour regrouper par couple (client, produit)
|
||||
cycle_data = {}
|
||||
|
||||
for line in sale_order_lines:
|
||||
key = (line.order_id.partner_id.id, line.product_id.id)
|
||||
if key not in cycle_data:
|
||||
cycle_data[key] = {
|
||||
'partner_id': line.order_id.partner_id.id,
|
||||
'product_id': line.product_id.id,
|
||||
'sale_order_line_ids': []
|
||||
}
|
||||
cycle_data[key]['sale_order_line_ids'].append(line.id) # Ajouter l'ID de la ligne
|
||||
|
||||
# Créer les enregistrements manquants dans Itch Cycle
|
||||
for key, data in cycle_data.items():
|
||||
partner_id, product_id = key
|
||||
|
||||
# Vérifier si l'enregistrement existe déjà
|
||||
itch_cycle = self.search([('partner_id', '=', partner_id), ('product_id', '=', product_id)], limit=1)
|
||||
|
||||
if not itch_cycle:
|
||||
# Calculer le cycle moyen basé sur les dates de commandes
|
||||
order_dates = sorted([self.env['sale.order.line'].browse(line_id).order_id.date_order
|
||||
for line_id in data['sale_order_line_ids']])
|
||||
if len(order_dates) > 1:
|
||||
intervals = [(order_dates[i + 1] - order_dates[i]).days for i in range(len(order_dates) - 1)]
|
||||
average_cycle = sum(intervals) // len(intervals) if intervals else 0
|
||||
else:
|
||||
average_cycle = 0
|
||||
|
||||
# Créer l'enregistrement dans la table Itch Cycle
|
||||
if product_id and partner_id:
|
||||
self.create({
|
||||
'partner_id': partner_id,
|
||||
'product_id': product_id,
|
||||
'sale_order_line_ids': [(6, 0, data['sale_order_line_ids'])]
|
||||
})
|
||||
else:
|
||||
#raise UserError("Impossible de créer un cycle sans client ou produit associé.")
|
||||
print("Impossible de créer un cycle sans client ou produit associé.")
|
||||
print('valeur de product_id', product_id)
|
||||
print('valeur de partner_id', partner_id)
|
||||
else:
|
||||
# Mettre à jour les lignes de commande si nécessaire
|
||||
itch_cycle.write({
|
||||
'sale_order_line_ids': [(6, 0, data['sale_order_line_ids'])], # Lier ou actualiser les lignes
|
||||
})
|
||||
return True
|
||||
|
|
|
|||
15
customer_itch_cycle/models/product_category.py
Normal file
15
customer_itch_cycle/models/product_category.py
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
from odoo import models, fields
|
||||
|
||||
class ProductCategory(models.Model):
|
||||
_inherit = 'product.category'
|
||||
|
||||
seasonal_factor = fields.Boolean(
|
||||
string="Catégorie saisonnière",
|
||||
default=False
|
||||
)
|
||||
|
||||
season_months = fields.Char(
|
||||
string="Mois actifs",
|
||||
help="Mois pendant lesquels cette catégorie est active (ex: '3,4,5' pour mars-mai)"
|
||||
)
|
||||
33
customer_itch_cycle/models/res_partner.py
Normal file
33
customer_itch_cycle/models/res_partner.py
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from datetime import datetime
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
itch_cycle_product_ids = fields.One2many(
|
||||
comodel_name='itch.cycle.product.partner',
|
||||
inverse_name='partner_id',
|
||||
string="Itch Cycles Produits"
|
||||
)
|
||||
|
||||
itch_next_delay = fields.Date(
|
||||
string="Prochaine Date de Suivi (Itch-Cycle Min)",
|
||||
compute="_compute_itch_next_delay",
|
||||
store=True
|
||||
)
|
||||
|
||||
@api.depends('itch_cycle_product_ids.next_follow_up_date')
|
||||
def _compute_itch_next_delay(self):
|
||||
"""
|
||||
Calcule la date de suivi minimale parmi tous les cycles de produits associés.
|
||||
"""
|
||||
for partner in self:
|
||||
follow_up_dates = partner.itch_cycle_product_ids.mapped('next_follow_up_date')
|
||||
partner.itch_next_delay = min(follow_up_dates) if follow_up_dates else False
|
||||
|
||||
def action_populate_itch_cycles(self):
|
||||
"""
|
||||
Action bouton qui appelle la méthode pour peupler les cycles depuis les données passées.
|
||||
"""
|
||||
self.env['itch.cycle.product.partner'].populate_from_past_orders()
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError
|
||||
from datetime import datetime
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
def action_confirm(self):
|
||||
super(SaleOrder, self).action_confirm()
|
||||
for line in self.order_line:
|
||||
partner_id = self.partner_id
|
||||
product_id = line.product_id
|
||||
|
||||
itch_cycle_record = self.env['itch_cycle_product_partner'].search([
|
||||
('partner_id', '=', partner_id.id),
|
||||
('product_id', '=', product_id.id)
|
||||
], limit=1)
|
||||
|
||||
if itch_cycle_record:
|
||||
if itch_cycle_record.last_purchase_date:
|
||||
days_since_last_purchase = (datetime.now().date() - itch_cycle_record.last_purchase_date).days
|
||||
if itch_cycle_record.itch_cycle_duration == 0:
|
||||
raise UserError(_(
|
||||
f"Veuillez définir la durée du itch-cycle pour le produit '{product_id.name}' "
|
||||
f"pour le client '{partner_id.name}'.\n\n"
|
||||
f"Il y a eu {days_since_last_purchase} jours depuis le dernier achat."
|
||||
))
|
||||
else:
|
||||
itch_cycle_record.last_purchase_date = datetime.now().date()
|
||||
itch_cycle_record.itch_cycle_duration = days_since_last_purchase
|
||||
else:
|
||||
itch_cycle_record.last_purchase_date = datetime.now().date()
|
||||
else:
|
||||
new_record = self.env['itch_cycle_product_partner'].create({
|
||||
'partner_id': partner_id.id,
|
||||
'product_id': product_id.id,
|
||||
'last_purchase_date': datetime.now().date(),
|
||||
'itch_cycle_duration': 0
|
||||
})
|
||||
raise UserError(_(
|
||||
f"Il n'y a pas encore de itch-cycle défini pour le produit '{product_id.name}' "
|
||||
f"avec le client '{partner_id.name}'.\n\nVeuillez entrer une durée pour ce cycle."
|
||||
))
|
||||
27
customer_itch_cycle/models/sale_order_line.py
Normal file
27
customer_itch_cycle/models/sale_order_line.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
from odoo import models, fields, api
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = 'sale.order.line'
|
||||
|
||||
itch_cycle_id = fields.Many2one(
|
||||
comodel_name='itch.cycle.product.partner',
|
||||
string="Cycle Produit/Partenaire"
|
||||
)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
line = super(SaleOrderLine, self).create(vals)
|
||||
# Associer au bon cycle produit/partenaire
|
||||
if vals.get('product_id') and vals.get('order_id'):
|
||||
partner_id = self.env['sale.order'].browse(vals['order_id']).partner_id.id
|
||||
itch_cycle = self.env['itch.cycle.product.partner'].search([
|
||||
('partner_id', '=', partner_id),
|
||||
('product_id', '=', vals['product_id'])
|
||||
], limit=1)
|
||||
if not itch_cycle:
|
||||
itch_cycle = self.env['itch.cycle.product.partner'].create({
|
||||
'partner_id': partner_id,
|
||||
'product_id': vals['product_id'],
|
||||
})
|
||||
line.itch_cycle_id = itch_cycle.id
|
||||
return line
|
||||
2
customer_itch_cycle/security/ir.model.access.csv
Normal file
2
customer_itch_cycle/security/ir.model.access.csv
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_itch_cycle_product_partner,itch.cycle.product.partner access,model_itch_cycle_product_partner,base.group_user,1,1,1,1
|
||||
|
0
customer_itch_cycle/views/itch_cycle_menu.xml
Normal file
0
customer_itch_cycle/views/itch_cycle_menu.xml
Normal file
|
|
@ -1,44 +1,71 @@
|
|||
|
||||
<odoo>
|
||||
<record id="view_itch_cycle_product_partner_tree" model="ir.ui.view">
|
||||
<field name="name">itch.cycle.product.partner.tree</field>
|
||||
<field name="model">itch_cycle_product_partner</field>
|
||||
<field name="model">itch.cycle.product.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="partner_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="last_purchase_date"/>
|
||||
<field name="itch_cycle_duration"/>
|
||||
<field name="average_cycle"/>
|
||||
<field name="last_purchase_date"/>
|
||||
<field name="next_expected_date"/>
|
||||
<field name="next_follow_up_date"/>
|
||||
<field name="prediction_status"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_itch_cycle_product_partner_form" model="ir.ui.view">
|
||||
<field name="name">itch.cycle.product.partner.form</field>
|
||||
<field name="model">itch_cycle_product_partner</field>
|
||||
<field name="model">itch.cycle.product.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<header>
|
||||
<field name="prediction_status" widget="statusbar" options="{'on_time': 'green', 'delayed': 'red'}"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="partner_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="last_purchase_date"/>
|
||||
<field name="itch_cycle_duration"/>
|
||||
<field name="next_follow_up_date"/>
|
||||
<group string="Informations principales">
|
||||
<field name="partner_id"/>
|
||||
<field name="product_id"/>
|
||||
</group>
|
||||
<group string="Statistiques">
|
||||
<field name="itch_cycle_duration" readonly="1"/>
|
||||
<field name="average_cycle" readonly="1"/>
|
||||
<field name="last_purchase_date" readonly="1"/>
|
||||
<field name="next_expected_date" readonly="1"/>
|
||||
<field name="next_follow_up_date"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Lignes de commandes associées">
|
||||
<field name="sale_order_line_ids">
|
||||
<tree editable="bottom">
|
||||
<field name="order_id"/>
|
||||
<field name="product_id"/>
|
||||
<field name="price_unit"/>
|
||||
<field name="product_uom_qty"/>
|
||||
<field name="discount"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_itch_cycle_product_partner" name="Itch Cycles"
|
||||
parent="sale.sale_order_menu"
|
||||
action="action_itch_cycle_product_partner"/>
|
||||
|
||||
<record id="action_itch_cycle_product_partner" model="ir.actions.act_window">
|
||||
<field name="name">Itch Cycles</field>
|
||||
<field name="res_model">itch_cycle_product_partner</field>
|
||||
<field name="name">Itch Cycles Produits</field>
|
||||
<field name="res_model">itch.cycle.product.partner</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_itch_cycle_product_partner_tree"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
<menuitem id="menu_itch_cycle_product_root"
|
||||
name="Itch Cycle"
|
||||
sequence="10"
|
||||
parent="sale.menu_sale_report"
|
||||
action="action_itch_cycle_product_partner"/>
|
||||
</odoo>
|
||||
21
customer_itch_cycle/views/product_category_view.xml
Normal file
21
customer_itch_cycle/views/product_category_view.xml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
|
||||
<odoo>
|
||||
<record id="view_product_category_form" model="ir.ui.view">
|
||||
<field name="name">product.category.form</field>
|
||||
<field name="model">product.category</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Catégorie de produit">
|
||||
<sheet>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="parent_id"/>
|
||||
</group>
|
||||
<group string="Saisonnalité">
|
||||
<field name="seasonal_factor"/>
|
||||
<field name="season_months"/>
|
||||
</group>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
@ -5,19 +5,25 @@
|
|||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<sheet position="before">
|
||||
<group string="Itch Cycle Information">
|
||||
<field name="itch_next_delay" readonly="1"/>
|
||||
<field name="itch_cycle_product_ids" readonly="1">
|
||||
<tree>
|
||||
<field name="product_id"/>
|
||||
<field name="last_purchase_date"/>
|
||||
<field name="itch_cycle_duration"/>
|
||||
<field name="next_follow_up_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</sheet>
|
||||
<notebook position="inside">
|
||||
<page string="Itch Cycle" name="itch_cycle">
|
||||
<button name="action_populate_itch_cycles"
|
||||
string="Traiter l'historique des cycles"
|
||||
type="object"
|
||||
class="btn-primary"/>
|
||||
<group string="Itch Cycle Information">
|
||||
<field name="itch_next_delay" readonly="1"/>
|
||||
<field name="itch_cycle_product_ids" readonly="1">
|
||||
<tree>
|
||||
<field name="product_id"/>
|
||||
<field name="last_purchase_date"/>
|
||||
<field name="itch_cycle_duration"/>
|
||||
<field name="next_follow_up_date"/>
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
|
|
|||
|
|
@ -57,6 +57,8 @@ class PartnerPurchaseAnalysisWizard(models.TransientModel):
|
|||
if self.date_end:
|
||||
domain.append(('order_id.date_order', '<=', self.date_end))
|
||||
|
||||
domain.append(('order_id.state', 'in', ['sale', 'done']))
|
||||
|
||||
sale_order_lines = self.env['sale.order.line'].search(domain)
|
||||
|
||||
if not sale_order_lines:
|
||||
|
|
@ -82,10 +84,14 @@ class PartnerPurchaseAnalysisWizard(models.TransientModel):
|
|||
user_lang_name = self.env['res.lang'].search([('code', '=', user_lang)], limit=1).name or "English"
|
||||
|
||||
prompt = (
|
||||
"Analyze the following customer purchase history. Identify trends, product "
|
||||
"category preferences, and any significant deviations. Respond in "
|
||||
f"{user_lang_name}. Produce graph and table of the analysis. You output all "
|
||||
"in html format."
|
||||
"Analyze all the sale order lines of the following customer. Identify trends, "
|
||||
"and any significant deviations. Respond in "
|
||||
f"{user_lang_name}. Produce the analysis adding next plan purchase or lost purchase. You output all "
|
||||
"in html format. Focus on missing product order and deviation from the average. "
|
||||
"Be sure to list all products and categories in the analysis. Try to identify "
|
||||
"the next purchase date for all product and warn if the customer is not buying "
|
||||
"and identify recurring sale and product not sale. Put in the analysis if the product is not bought "
|
||||
"in the last 12 months and show those product as lost sale with a value of the lost sales"
|
||||
)
|
||||
|
||||
# Construction de `purchase_details` pour le contenu du prompt
|
||||
|
|
|
|||
Loading…
Reference in a new issue