/
Paff
/
declarant
Обзор
Документация
Войти
/
Paff
/
declarant
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
firm_rules.py
184 строки
8 KB
1pash1985-gif
LPD555: col/ecu/ken path patterns + BOJ444 cert AWB + packing fixes
26 июл 2026, 18:59
26 июл 2026, 18:59
59dc6f7
Код
Авторство
О чём код?
# -*- coding: utf-8 -*- """ Правила определения "Фирмы" (столбец A листа "Загрузка") и "Маркировки" (столбец D) по имени файла инвойса и/или его пути. Логика (в порядке приоритета): 1. По имени файла — детерминированные паттерны (`Invoice 309*.xls` → AstraFund). 2. По имени родительской папки — для 700ecu/MTL700 Kenya/MTL700 Columbia. 3. По содержимому инвойса (shipper/farm — опционально, следующая итерация). Также извлекается MARKING — короткий код для столбца D. """ from __future__ import annotations import os import re from dataclasses import dataclass from typing import Optional @dataclass class FirmMatch: firm: str = "" # значение для столбца A marking: str = "" # значение для столбца D awb_prefix: str = "" # первые 4 цифры имени папки — префикс AWB country: str = "" # Ecuador/Colombia/Kenya/… (если можно определить по пути) # === Правила по имени файла (03-MTL700 — европейские фермы через хендлеров) === # Порядок важен: более специфичные — выше. FILENAME_RULES: list[tuple[str, str]] = [ # BESTFLORA-2_b-XXX_DD_Mon_YYYY.xlsx → eFlowers (r'^BESTFLORA-\d+_b-', 'eFlowers'), # Invoice 309XXX ... .xls → AstraFund (r'^Invoice\s+309\d{3,4}\s', 'AstraFund'), # 8207XXX POPBES XXX.XLS → FlowerSaleForever (r'^8207\d{3}\s+POPBES', 'FlowerSaleForever'), # 2261XXX IZUM.XLS → Zeester (нужно проверить ДО правила M&M ниже — оба матчат # 03-07-26 HH-MM-SS-NNNNNNN формат) (r'^\d{2}-\d{2}-\d{2}\s+\d{2}-\d{2}-\d{2}-2261\d{3}\s', 'Zeester'), # MAX12 522.XLS → ButaFlowers (r'^MAX12\s', 'ButaFlowers'), # Invoice - 6NNNNN.xlsx → OzExport (голландский поставщик Florunner B.V. - # в мастере эти инвойсы декларант ставит под фирму «OzExport»). Маркировка # и точное число боксов извлекаются отдельным парсером florunner_parser.py # по внутренней структуре (Debnr → маркировка; Colli → боксы). (r'^Invoice\s*-\s*6\d{5}\.', 'OzExport'), # 03-07-26 HH-MM-SS-2026XXXX YYY.XLS → M&M (id начинается с 2026) (r'^\d{2}-\d{2}-\d{2}\s+\d{2}-\d{2}-\d{2}-2026\d{4}\s', 'M&M'), # Fallback: любой файл 03-07-26 HH-MM-SS-* без специфичного префикса (r'^\d{2}-\d{2}-\d{2}\s+\d{2}-\d{2}-\d{2}-', 'M&M'), # Factuur_XX.xlsx → OzExport / Dutch (r'^Factuur_\d', 'OzExport'), # Общий "Invoice - NNNNNN.xlsx" (может быть Enigma/AstraFund/…) — оставляем # фирму пустой, заполнится через shipper внутри инвойса. ] # === Правила по имени папки (Инвойсы/700ecu/NNNN NAME/ ...) === # NNNN — AWB prefix. NAME — обычно совпадает с маркировкой. FOLDER_RULES_ECU: list[tuple[str, str]] = [ # Специфичные case-ы, где Firm != NAME # (пока пусто; при необходимости — дополним) ] # === Ключи страны по подпапке инвойсов === COUNTRY_BY_PATH: list[tuple[str, str]] = [ (r'MTL\d*\s*Kenya', 'Kenya'), (r'MTL\d*\s*Columbia', 'Colombia'), (r'MTL\d*\s*Colombia', 'Colombia'), # Папки вида <CAR>ecu / <CAR>ken / <CAR>col: 700ecu, 856ecu, 856ken, 856col … (r'\b\d{3,4}ecu\b', 'Ecuador'), (r'\b\d{3,4}ken\b', 'Kenya'), (r'\b\d{3,4}col\b', 'Colombia'), # Standalone col/ ecu/ ken/ subfolders (from rar extraction) (r'[/\\]col[/\\]', 'Colombia'), (r'[/\\]ecu[/\\]', 'Ecuador'), (r'[/\\]ken[/\\]', 'Kenya'), (r'\b03-MTL', 'Netherlands'), # прибытие через Голландию (хендлеры EU) ] def detect_firm_and_marking(file_path: str) -> FirmMatch: """Основная точка входа: определить Фирму, Маркировку, AWB-префикс, Страну по пути.""" m = FirmMatch() fname = os.path.basename(file_path) dirname = os.path.basename(os.path.dirname(file_path)) full_path = file_path.replace('\\', '/') # 1. Страна — по пути for pattern, country in COUNTRY_BY_PATH: if re.search(pattern, full_path, re.IGNORECASE): m.country = country break # 2. AWB-префикс + маркировка — из имени родительской папки для 700ecu/Kenya/Columbia # Шаблон папки: "NNNN NAME1 NAME2 …" folder_awb_match = re.match(r'^(\d{4})\s+(.+?)(?:\s+\d+кор)?$', dirname) if folder_awb_match: m.awb_prefix = folder_awb_match.group(1) m.marking = folder_awb_match.group(2).strip().upper() # 3. Фирма — по имени файла (правила 03-MTL700) for pattern, firm in FILENAME_RULES: if re.match(pattern, fname, re.IGNORECASE): m.firm = firm break # 4. Маркировка — из имени файла для 03-MTL700 (если ещё не задана папкой) if not m.marking: m.marking = _extract_marking_from_filename(fname) # 5. Для 700ecu-папок фирма определяется по shipper внутри — пока оставляем пусто, # заполнитель проставит по факту разбора инвойса. return m def _extract_marking_from_filename(fname: str) -> str: """Достать «маркировочный» токен из имени файла. Примеры: "03-07-26 18-19-59-202603994 MUST.XLS" → "MUST" "03-07-26 18-24-46-202603995 PRADZ - B.XLS" → "PRADZ" "8207560 POPBES BUTA.XLS" → "BUTA" "BESTFLORA-2_b-BOOM55_03_Jul_2026.xlsx" → "B-BOOM55" "Invoice 309871 03-07-2026 BORT-20.xls" → "BORT-20" "MAX12 522.XLS" → "MAX" """ stem = os.path.splitext(fname)[0] # Пропускаем PRO FORMA (это не инвойс, а проформа) if re.match(r'.*PRO\s*FORMA', stem, re.IGNORECASE): return "" # BESTFLORA-2_b-XXX_DD_Mon_YYYY → "B-XXX" (XXX может содержать точку: KAZAN.MAXIBON) m = re.match(r'^BESTFLORA-\d+_(b-[\w.]+?)_\d{2}_[A-Za-z]{3}_\d{4}', stem, re.IGNORECASE) if m: return m.group(1).upper() # Invoice 309XXX 03-07-2026 NAME → "NAME" m = re.match(r'^Invoice\s+\d+\s+\d{2}-\d{2}-\d{4}\s+(.+)$', stem, re.IGNORECASE) if m: return m.group(1).strip().upper() # 8207NNN POPBES NAME → "NAME" m = re.match(r'^\d{7}\s+POPBES\s+(\S+)', stem, re.IGNORECASE) if m: return m.group(1).upper() # 2261659 IZUM → "IZUM" m = re.match(r'^\d{7}\s+(\S+)', stem) if m: return m.group(1).upper() # 03-07-26 18-19-59-NNNNN MUST (несколько пробелов — разделитель) m = re.match(r'^\d{2}-\d{2}-\d{2}\s+\d{2}-\d{2}-\d{2}-\S+\s+(\S+)', stem) if m: return m.group(1).upper() # MAX12 522 → "MAX" m = re.match(r'^([A-Z]{3,})\d*\s', stem) if m: return m.group(1).upper() # Factuur_26.7706684 → "" (маркировка отсутствует, определится по shipper-у) if re.match(r'^Factuur', stem, re.IGNORECASE): return "" return "" if __name__ == '__main__': import sys try: sys.stdout.reconfigure(encoding='utf-8') except Exception: pass root = r'c:\Users\0\Desktop\Задача по логистике\03.07.2026\MTL 700\Инвойсы' for dirpath, dirs, files in os.walk(root): for f in files: if f.lower().endswith(('.pdf', '.xls', '.xlsx', '.xlsm')): fp = os.path.join(dirpath, f) m = detect_firm_and_marking(fp) rel = os.path.relpath(fp, root) print(f'{rel:80s} | firm={m.firm:20s} mark={m.marking:20s} ' f'awb={m.awb_prefix:5s} country={m.country}')