Align cutting families with Olist production data
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 1m17s
Some checks failed
Build and Deploy / build-and-deploy (push) Failing after 1m17s
This commit is contained in:
@@ -45,7 +45,9 @@ const productionOrder = (overrides: Partial<ProductionOrderItem>): ProductionOrd
|
||||
test('classifyCutFamily maps known product bases to internal cut families', () => {
|
||||
assert.equal(classifyCutFamily('BASE LISA CAMISETA').key, 'BLCS');
|
||||
assert.equal(classifyCutFamily('BASE LISA CAMISETA OVER').key, 'BLOS');
|
||||
assert.equal(classifyCutFamily('BASE LISA MOLETOM CANGURU').key, 'BLPM');
|
||||
assert.equal(classifyCutFamily('BASE LISA MOLETOM CANGURU').key, 'BLMC');
|
||||
assert.equal(classifyCutFamily('BASE LISA CAMISETA PIMA').key, 'BLPM');
|
||||
assert.equal(classifyCutFamily('BASE LISA REGATA MACHAO').key, 'BLRM');
|
||||
assert.equal(classifyCutFamily('BONÉ').key, 'OUTROS');
|
||||
});
|
||||
|
||||
|
||||
@@ -70,10 +70,10 @@ export interface CutPlan {
|
||||
|
||||
export const CUT_FAMILY_RULES: CutFamilyRule[] = [
|
||||
{
|
||||
key: 'BLPM',
|
||||
label: 'Moletom',
|
||||
materialLabel: 'BLPM',
|
||||
keywords: ['MOLETOM'],
|
||||
key: 'BLMC',
|
||||
label: 'Moletom canguru',
|
||||
materialLabel: 'BLMC',
|
||||
keywords: ['MOLETOM CANGURU', 'MOLETOM'],
|
||||
unitsPerRoll: null
|
||||
},
|
||||
{
|
||||
@@ -84,10 +84,17 @@ export const CUT_FAMILY_RULES: CutFamilyRule[] = [
|
||||
unitsPerRoll: null
|
||||
},
|
||||
{
|
||||
key: 'BLMC',
|
||||
label: 'Camiseta infantil',
|
||||
materialLabel: 'BLMC',
|
||||
keywords: ['INFANTIL', 'KIDS'],
|
||||
key: 'BLPM',
|
||||
label: 'Camiseta Pima',
|
||||
materialLabel: 'BLPM',
|
||||
keywords: ['CAMISETA PIMA', 'PIMA'],
|
||||
unitsPerRoll: null
|
||||
},
|
||||
{
|
||||
key: 'BLRM',
|
||||
label: 'Regata',
|
||||
materialLabel: 'BLRM',
|
||||
keywords: ['REGATA'],
|
||||
unitsPerRoll: null
|
||||
},
|
||||
{
|
||||
|
||||
@@ -43,7 +43,7 @@ const issueLabels: Record<CutIssue, string> = {
|
||||
};
|
||||
|
||||
const issueHelp: Record<CutIssue, string> = {
|
||||
missing_family_rule: 'Produto não caiu em BLCS, BLOS, BLMC ou BLPM.',
|
||||
missing_family_rule: 'Produto não caiu em BLCS, BLOS, BLMC, BLPM ou BLRM.',
|
||||
missing_color: 'Nome do produto não tem uma cor clara para montar matriz de corte.',
|
||||
missing_size: 'Nome do produto não tem tamanho claro para montar matriz de corte.',
|
||||
missing_yield_rule: 'Família reconhecida, mas ainda falta cadastrar unidades por rolo.'
|
||||
@@ -61,6 +61,7 @@ const familyStyles: Record<CutFamilyKey, string> = {
|
||||
BLOS: 'border-sky-400/30 bg-sky-400/10 text-sky-300',
|
||||
BLMC: 'border-amber-400/30 bg-amber-400/10 text-amber-300',
|
||||
BLPM: 'border-purple-400/30 bg-purple-400/10 text-purple-300',
|
||||
BLRM: 'border-rose-400/30 bg-rose-400/10 text-rose-300',
|
||||
OUTROS: 'border-zinc-500/30 bg-zinc-500/10 text-zinc-300'
|
||||
};
|
||||
|
||||
@@ -1005,7 +1006,7 @@ const Cutting = () => {
|
||||
</div>
|
||||
|
||||
{settingsSection === 'rules' && (
|
||||
<div className="grid grid-cols-1 gap-3 md:grid-cols-4">
|
||||
<div className="grid grid-cols-1 gap-3 md:grid-cols-5">
|
||||
{CUT_FAMILY_RULES.map(rule => (
|
||||
<label key={rule.key} className="rounded-xl border border-dark-border bg-dark-input p-3">
|
||||
<span className="mb-2 flex items-center justify-between gap-2">
|
||||
|
||||
@@ -38,6 +38,14 @@ const runStatusLabel = (run: OlistSyncRun) => (
|
||||
: 'Concluída'
|
||||
);
|
||||
|
||||
const yieldFamilyLabels: Record<string, string> = {
|
||||
BLCS: 'Camiseta regular',
|
||||
BLOS: 'Oversize',
|
||||
BLMC: 'Moletom canguru',
|
||||
BLPM: 'Camiseta Pima',
|
||||
BLRM: 'Regata'
|
||||
};
|
||||
|
||||
const OlistSync = () => {
|
||||
const [status, setStatus] = useState<OlistStatus | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
@@ -290,16 +298,22 @@ const OlistSync = () => {
|
||||
</div>
|
||||
<button type="button" onClick={() => void loadImportData()} title="Atualizar importações" aria-label="Atualizar importações" className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-dark-border text-brand-primary transition-colors hover:border-brand-primary cursor-pointer"><RefreshCw className="h-4 w-4" /></button>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-3 p-5 md:grid-cols-4">
|
||||
{(['BLCS', 'BLOS', 'BLMC', 'BLPM'] as const).map(familyKey => {
|
||||
<div className="grid grid-cols-1 gap-3 p-5 md:grid-cols-5">
|
||||
{(['BLCS', 'BLOS', 'BLMC', 'BLPM', 'BLRM'] as const).map(familyKey => {
|
||||
const recommendation = importData?.recommendations.find(item => item.familyKey === familyKey);
|
||||
return <div key={familyKey} className="rounded-xl border border-dark-border bg-dark-input/50 p-3">
|
||||
<p className="text-[10px] font-bold uppercase tracking-widest text-dark-muted">{familyKey}</p>
|
||||
<p className="text-[10px] font-bold uppercase tracking-widest text-dark-muted">{familyKey} · {yieldFamilyLabels[familyKey]}</p>
|
||||
<p className="mt-2 text-lg font-bold text-dark-text">{recommendation?.recommendedUnitsPerRoll ? `${Math.round(recommendation.recommendedUnitsPerRoll).toLocaleString('pt-BR')} un./rolo` : 'Sem sugestão'}</p>
|
||||
<p className="mt-1 text-xs font-semibold text-dark-muted">{recommendation ? `${recommendation.sampleCount.toLocaleString('pt-BR')} OPs · ${recommendation.yieldSampleCount.toLocaleString('pt-BR')} c/ rendimento` : 'Nenhuma OP importada'}</p>
|
||||
</div>;
|
||||
})}
|
||||
</div>
|
||||
{!!importData?.supplierRecommendations.length && <div className="border-t border-dark-border px-5 pb-5 pt-4">
|
||||
<p className="text-[10px] font-bold uppercase tracking-widest text-dark-muted">Referências por fornecedor</p>
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
{importData.supplierRecommendations.filter(item => item.recommendedUnitsPerRoll).map(item => <span key={`${item.familyKey}-${item.supplier}`} className="rounded-full border border-brand-primary/30 bg-brand-primary/10 px-2.5 py-1 text-xs font-bold text-brand-primary">{item.familyKey} · {item.supplier}: {Math.round(item.recommendedUnitsPerRoll!).toLocaleString('pt-BR')} un./rolo</span>)}
|
||||
</div>
|
||||
</div>}
|
||||
<div className="divide-y divide-dark-border">
|
||||
{!importData?.runs.length && <p className="p-5 text-sm font-semibold text-dark-muted">Nenhum CSV de OPs finalizadas importado.</p>}
|
||||
{importData?.runs.map(run => <div key={run.id} className="flex flex-col gap-2 p-4 md:flex-row md:items-center md:justify-between">
|
||||
|
||||
@@ -126,7 +126,7 @@ export interface CreateProductionOrdersResult {
|
||||
}>;
|
||||
}
|
||||
|
||||
export type CutFamilyKey = 'BLCS' | 'BLOS' | 'BLMC' | 'BLPM' | 'OUTROS';
|
||||
export type CutFamilyKey = 'BLCS' | 'BLOS' | 'BLMC' | 'BLPM' | 'BLRM' | 'OUTROS';
|
||||
|
||||
export interface CutProductOverride {
|
||||
familyKey?: CutFamilyKey | '';
|
||||
@@ -272,7 +272,7 @@ export interface ProductionOrderImportRun {
|
||||
}
|
||||
|
||||
export interface ProductionYieldRecommendation {
|
||||
familyKey: 'BLCS' | 'BLOS' | 'BLMC' | 'BLPM';
|
||||
familyKey: 'BLCS' | 'BLOS' | 'BLMC' | 'BLPM' | 'BLRM';
|
||||
sampleCount: number;
|
||||
yieldSampleCount: number;
|
||||
rollSampleCount: number;
|
||||
@@ -283,9 +283,14 @@ export interface ProductionYieldRecommendation {
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface ProductionYieldSupplierRecommendation extends ProductionYieldRecommendation {
|
||||
supplier: string;
|
||||
}
|
||||
|
||||
export interface ProductionOrderImportData {
|
||||
runs: ProductionOrderImportRun[];
|
||||
recommendations: ProductionYieldRecommendation[];
|
||||
supplierRecommendations: ProductionYieldSupplierRecommendation[];
|
||||
}
|
||||
|
||||
export type CatalogProductPayload = {
|
||||
|
||||
Reference in New Issue
Block a user