ai说excel部分没问题了,暂且信一次,提交文件
This commit is contained in:
Binary file not shown.
+271
-158
@@ -1,30 +1,26 @@
|
||||
"""
|
||||
单位转换处理模块
|
||||
-------------
|
||||
提供规格和单位的处理和转换功能。
|
||||
单位转换模块
|
||||
----------
|
||||
提供单位转换功能,支持规格推断和单位自动提取。
|
||||
"""
|
||||
|
||||
import re
|
||||
from typing import Dict, List, Optional, Tuple, Any
|
||||
import logging
|
||||
from typing import Dict, Tuple, Optional, Any, List, Union
|
||||
|
||||
from ..utils.log_utils import get_logger
|
||||
from ..utils.string_utils import (
|
||||
clean_string,
|
||||
extract_number,
|
||||
extract_unit,
|
||||
extract_number_and_unit,
|
||||
parse_specification
|
||||
)
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
class UnitConverter:
|
||||
"""
|
||||
单位转换器:处理商品规格和单位转换
|
||||
单位转换器:处理不同单位之间的转换,支持从商品名称推断规格
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""初始化单位转换器"""
|
||||
"""
|
||||
初始化单位转换器
|
||||
"""
|
||||
# 特殊条码配置
|
||||
self.special_barcodes = {
|
||||
'6925019900087': {
|
||||
@@ -32,182 +28,299 @@ class UnitConverter:
|
||||
'target_unit': '瓶', # 目标单位
|
||||
'description': '特殊处理:数量*10,单位转换为瓶'
|
||||
}
|
||||
# 可以在这里添加更多特殊条码的配置
|
||||
# 可以添加更多特殊条码的配置
|
||||
}
|
||||
|
||||
# 有效的单位列表
|
||||
self.valid_units = ['件', '箱', '包', '提', '盒', '瓶', '个', '支', '袋', '副', '桶', '罐', 'L', 'l', '升']
|
||||
|
||||
# 需要特殊处理的单位
|
||||
self.special_units = ['件', '箱', '提', '盒']
|
||||
|
||||
logger.info("单位转换器初始化完成")
|
||||
# 规格推断的正则表达式模式
|
||||
self.spec_patterns = [
|
||||
# 1*6、1x12、1X20等格式
|
||||
(r'(\d+)[*xX×](\d+)', r'\1*\2'),
|
||||
# 1*5*12和1x5x12等三级格式
|
||||
(r'(\d+)[*xX×](\d+)[*xX×](\d+)', r'\1*\2*\3'),
|
||||
# "xx入"格式,如"12入"、"24入"
|
||||
(r'(\d+)入', r'1*\1'),
|
||||
# "xxL*1"或"xx升*1"格式
|
||||
(r'([\d\.]+)[L升][*xX×]?(\d+)?', r'\1L*\2' if r'\2' else r'\1L*1'),
|
||||
# "xxkg*1"或"xx公斤*1"格式
|
||||
(r'([\d\.]+)(?:kg|公斤)[*xX×]?(\d+)?', r'\1kg*\2' if r'\2' else r'\1kg*1'),
|
||||
# "xxg*1"或"xx克*1"格式
|
||||
(r'([\d\.]+)(?:g|克)[*xX×]?(\d+)?', r'\1g*\2' if r'\2' else r'\1g*1'),
|
||||
# "xxmL*1"或"xx毫升*1"格式
|
||||
(r'([\d\.]+)(?:mL|毫升)[*xX×]?(\d+)?', r'\1mL*\2' if r'\2' else r'\1mL*1'),
|
||||
]
|
||||
|
||||
def add_special_barcode(self, barcode: str, multiplier: int, target_unit: str, description: str = "") -> None:
|
||||
def extract_unit_from_quantity(self, quantity_str: str) -> Tuple[Optional[float], Optional[str]]:
|
||||
"""
|
||||
添加特殊条码处理配置
|
||||
从数量字符串中提取单位
|
||||
|
||||
Args:
|
||||
barcode: 条码
|
||||
multiplier: 数量乘数
|
||||
target_unit: 目标单位
|
||||
description: 处理描述
|
||||
quantity_str: 数量字符串,如"2箱"、"5件"
|
||||
|
||||
Returns:
|
||||
(数量, 单位)的元组,如果无法提取则返回(None, None)
|
||||
"""
|
||||
self.special_barcodes[barcode] = {
|
||||
'multiplier': multiplier,
|
||||
'target_unit': target_unit,
|
||||
'description': description or f'特殊处理:数量*{multiplier},单位转换为{target_unit}'
|
||||
}
|
||||
logger.info(f"添加特殊条码配置: {barcode}, {description}")
|
||||
if not quantity_str or not isinstance(quantity_str, str):
|
||||
return None, None
|
||||
|
||||
# 匹配数字+单位格式
|
||||
match = re.match(r'^([\d\.]+)\s*([^\d\s\.]+)$', quantity_str.strip())
|
||||
if match:
|
||||
try:
|
||||
num = float(match.group(1))
|
||||
unit = match.group(2)
|
||||
logger.info(f"从数量提取单位: {quantity_str} -> 数量={num}, 单位={unit}")
|
||||
return num, unit
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
return None, None
|
||||
|
||||
def infer_specification_from_name(self, product_name: str) -> Optional[str]:
|
||||
def extract_specification(self, text: str) -> Optional[str]:
|
||||
"""
|
||||
从商品名称推断规格
|
||||
从文本中提取规格信息
|
||||
|
||||
Args:
|
||||
product_name: 商品名称
|
||||
text: 文本字符串
|
||||
|
||||
Returns:
|
||||
提取的规格字符串,如果无法提取则返回None
|
||||
"""
|
||||
if not text or not isinstance(text, str):
|
||||
return None
|
||||
|
||||
# 尝试所有模式
|
||||
for pattern, replacement in self.spec_patterns:
|
||||
match = re.search(pattern, text)
|
||||
if match:
|
||||
# 特殊处理三级格式,确保正确显示为1*5*12
|
||||
if '*' in replacement and replacement.count('*') == 1 and len(match.groups()) >= 2:
|
||||
result = f"{match.group(1)}*{match.group(2)}"
|
||||
logger.info(f"提取规格: {text} -> {result}")
|
||||
return result
|
||||
# 特殊处理三级规格格式
|
||||
elif '*' in replacement and replacement.count('*') == 2 and len(match.groups()) >= 3:
|
||||
result = f"{match.group(1)}*{match.group(2)}*{match.group(3)}"
|
||||
logger.info(f"提取三级规格: {text} -> {result}")
|
||||
return result
|
||||
# 一般情况
|
||||
else:
|
||||
result = re.sub(pattern, replacement, text)
|
||||
logger.info(f"提取规格: {text} -> {result}")
|
||||
return result
|
||||
|
||||
# 没有匹配任何模式
|
||||
return None
|
||||
|
||||
def infer_specification_from_name(self, name: str) -> Optional[str]:
|
||||
"""
|
||||
从商品名称中推断规格
|
||||
|
||||
Args:
|
||||
name: 商品名称
|
||||
|
||||
Returns:
|
||||
推断的规格,如果无法推断则返回None
|
||||
"""
|
||||
if not product_name or not isinstance(product_name, str):
|
||||
if not name or not isinstance(name, str):
|
||||
return None
|
||||
|
||||
# 特殊模式的名称处理
|
||||
# 如"445水溶C血橙15入纸箱" -> "1*15"
|
||||
pattern1 = r'.*(\d+)入'
|
||||
match = re.match(pattern1, name)
|
||||
if match:
|
||||
inferred_spec = f"1*{match.group(1)}"
|
||||
logger.info(f"从名称推断规格(入): {name} -> {inferred_spec}")
|
||||
return inferred_spec
|
||||
|
||||
# 如"500-东方树叶-绿茶1*15-纸箱装" -> "1*15"
|
||||
pattern2 = r'.*(\d+)[*xX×](\d+).*'
|
||||
match = re.match(pattern2, name)
|
||||
if match:
|
||||
inferred_spec = f"{match.group(1)}*{match.group(2)}"
|
||||
logger.info(f"从名称推断规格(直接): {name} -> {inferred_spec}")
|
||||
return inferred_spec
|
||||
|
||||
# 如"12.9L桶装水" -> "12.9L*1"
|
||||
pattern3 = r'.*?([\d\.]+)L.*'
|
||||
match = re.match(pattern3, name)
|
||||
if match:
|
||||
inferred_spec = f"{match.group(1)}L*1"
|
||||
logger.info(f"从名称推断规格(L): {name} -> {inferred_spec}")
|
||||
return inferred_spec
|
||||
|
||||
# 从名称中提取规格
|
||||
spec = self.extract_specification(name)
|
||||
if spec:
|
||||
return spec
|
||||
|
||||
try:
|
||||
# 清理商品名称
|
||||
name = clean_string(product_name)
|
||||
|
||||
# 1. 匹配 XX入纸箱 格式
|
||||
match = re.search(r'(\d+)入纸箱', name)
|
||||
if match:
|
||||
return f"1*{match.group(1)}"
|
||||
|
||||
# 2. 匹配 绿茶1*15-纸箱装 格式
|
||||
match = re.search(r'(\d+)[*×xX](\d+)[-\s]?纸箱', name)
|
||||
if match:
|
||||
return f"{match.group(1)}*{match.group(2)}"
|
||||
|
||||
# 3. 匹配 12.9L桶装水 格式
|
||||
match = re.search(r'([\d\.]+)[Ll升](?!.*[*×xX])', name)
|
||||
if match:
|
||||
return f"{match.group(1)}L*1"
|
||||
|
||||
# 4. 匹配 商品12入纸箱 格式(数字在中间)
|
||||
match = re.search(r'\D(\d+)入\w*箱', name)
|
||||
if match:
|
||||
return f"1*{match.group(1)}"
|
||||
|
||||
# 5. 匹配 商品15纸箱 格式(数字在中间)
|
||||
match = re.search(r'\D(\d+)\w*箱', name)
|
||||
if match:
|
||||
return f"1*{match.group(1)}"
|
||||
|
||||
# 6. 匹配 商品1*30 格式
|
||||
match = re.search(r'(\d+)[*×xX](\d+)', name)
|
||||
if match:
|
||||
return f"{match.group(1)}*{match.group(2)}"
|
||||
|
||||
logger.debug(f"无法从商品名称推断规格: {name}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"从商品名称推断规格时出错: {e}")
|
||||
return None
|
||||
|
||||
def extract_unit_from_quantity(self, quantity_str: str) -> Tuple[Optional[float], Optional[str]]:
|
||||
return None
|
||||
|
||||
def parse_specification(self, spec: str) -> Tuple[int, int, Optional[int]]:
|
||||
"""
|
||||
从数量字符串提取单位
|
||||
解析规格字符串,支持1*12和1*5*12等格式
|
||||
|
||||
Args:
|
||||
quantity_str: 数量字符串
|
||||
spec: 规格字符串
|
||||
|
||||
Returns:
|
||||
(数量, 单位)元组
|
||||
(一级包装, 二级包装, 三级包装)元组,如果是二级包装,第三个值为None
|
||||
"""
|
||||
if not quantity_str or not isinstance(quantity_str, str):
|
||||
return None, None
|
||||
if not spec or not isinstance(spec, str):
|
||||
return 1, 1, None
|
||||
|
||||
try:
|
||||
# 清理数量字符串
|
||||
quantity_str = clean_string(quantity_str)
|
||||
|
||||
# 提取数字和单位
|
||||
return extract_number_and_unit(quantity_str)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"从数量字符串提取单位时出错: {quantity_str}, 错误: {e}")
|
||||
return None, None
|
||||
|
||||
def process_unit_conversion(self, product: Dict[str, Any]) -> Dict[str, Any]:
|
||||
# 处理三级包装,如1*5*12
|
||||
three_level_match = re.match(r'(\d+)[*xX×](\d+)[*xX×](\d+)', spec)
|
||||
if three_level_match:
|
||||
try:
|
||||
level1 = int(three_level_match.group(1))
|
||||
level2 = int(three_level_match.group(2))
|
||||
level3 = int(three_level_match.group(3))
|
||||
logger.info(f"解析三级规格: {spec} -> {level1}*{level2}*{level3}")
|
||||
return level1, level2, level3
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# 处理二级包装,如1*12
|
||||
two_level_match = re.match(r'(\d+)[*xX×](\d+)', spec)
|
||||
if two_level_match:
|
||||
try:
|
||||
level1 = int(two_level_match.group(1))
|
||||
level2 = int(two_level_match.group(2))
|
||||
logger.info(f"解析二级规格: {spec} -> {level1}*{level2}")
|
||||
return level1, level2, None
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# 特殊处理L/升为单位的规格,如12.5L*1
|
||||
volume_match = re.match(r'([\d\.]+)[L升][*xX×](\d+)', spec)
|
||||
if volume_match:
|
||||
try:
|
||||
volume = float(volume_match.group(1))
|
||||
quantity = int(volume_match.group(2))
|
||||
logger.info(f"解析容量规格: {spec} -> {volume}L*{quantity}")
|
||||
return 1, quantity, None
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# 默认值
|
||||
logger.warning(f"无法解析规格: {spec},使用默认值1*1")
|
||||
return 1, 1, None
|
||||
|
||||
def process_unit_conversion(self, product: Dict) -> Dict:
|
||||
"""
|
||||
处理单位转换,根据单位和规格转换数量和单价
|
||||
处理单位转换,按照以下规则:
|
||||
1. 特殊条码: 优先处理特殊条码
|
||||
2. "件"单位: 数量×包装数量, 单价÷包装数量, 单位转为"瓶"
|
||||
3. "箱"单位: 数量×包装数量, 单价÷包装数量, 单位转为"瓶"
|
||||
4. "提"和"盒"单位: 如果是三级规格, 按件处理; 如果是二级规格, 保持不变
|
||||
5. 其他单位: 保持不变
|
||||
|
||||
Args:
|
||||
product: 商品字典,包含条码、单位、规格、数量和单价等字段
|
||||
product: 商品信息字典
|
||||
|
||||
Returns:
|
||||
处理后的商品字典
|
||||
处理后的商品信息字典
|
||||
"""
|
||||
# 复制商品信息,避免修改原始数据
|
||||
# 复制原始数据,避免修改原始字典
|
||||
result = product.copy()
|
||||
|
||||
try:
|
||||
# 获取条码、单位、规格、数量和单价
|
||||
barcode = product.get('barcode', '')
|
||||
unit = product.get('unit', '')
|
||||
specification = product.get('specification', '')
|
||||
quantity = product.get('quantity', 0)
|
||||
price = product.get('price', 0)
|
||||
|
||||
# 如果缺少关键信息,无法进行转换
|
||||
if not barcode or quantity == 0:
|
||||
return result
|
||||
|
||||
# 1. 首先检查是否是特殊条码
|
||||
if barcode in self.special_barcodes:
|
||||
special_config = self.special_barcodes[barcode]
|
||||
logger.info(f"应用特殊条码配置: {barcode}, {special_config['description']}")
|
||||
|
||||
# 应用乘数和单位转换
|
||||
result['quantity'] = quantity * special_config['multiplier']
|
||||
result['unit'] = special_config['target_unit']
|
||||
|
||||
# 如果有单价,进行单价转换
|
||||
if price != 0:
|
||||
result['price'] = price / special_config['multiplier']
|
||||
|
||||
return result
|
||||
|
||||
# 2. 提取规格包装数量
|
||||
package_quantity = None
|
||||
if specification:
|
||||
package_quantity = parse_specification(specification)
|
||||
|
||||
# 3. 处理单位转换
|
||||
if unit and unit in self.special_units and package_quantity:
|
||||
# 判断是否是三级规格(1*5*12格式)
|
||||
is_three_level = bool(re.search(r'\d+[\*xX×]\d+[\*xX×]\d+', str(specification)))
|
||||
|
||||
# 对于"提"和"盒"单位的特殊处理
|
||||
if (unit in ['提', '盒']) and not is_three_level:
|
||||
# 二级规格:保持原数量不变
|
||||
logger.info(f"二级规格的提/盒单位,保持原状: {unit}, 规格={specification}")
|
||||
return result
|
||||
|
||||
# 标准处理:数量×包装数量,单价÷包装数量
|
||||
logger.info(f"标准单位转换: {unit}->瓶, 规格={specification}, 包装数量={package_quantity}")
|
||||
result['quantity'] = quantity * package_quantity
|
||||
result['unit'] = '瓶'
|
||||
|
||||
if price != 0:
|
||||
result['price'] = price / package_quantity
|
||||
|
||||
return result
|
||||
|
||||
# 4. 默认返回原始数据
|
||||
barcode = result.get('barcode', '')
|
||||
unit = result.get('unit', '')
|
||||
quantity = result.get('quantity', 0)
|
||||
price = result.get('price', 0)
|
||||
specification = result.get('specification', '')
|
||||
|
||||
# 跳过无效数据
|
||||
if not barcode or not quantity:
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"单位转换处理出错: {e}")
|
||||
# 发生错误时,返回原始数据
|
||||
return result
|
||||
# 特殊条码处理
|
||||
if barcode in self.special_barcodes:
|
||||
special_config = self.special_barcodes[barcode]
|
||||
multiplier = special_config.get('multiplier', 1)
|
||||
target_unit = special_config.get('target_unit', '瓶')
|
||||
|
||||
# 数量乘以倍数
|
||||
new_quantity = quantity * multiplier
|
||||
|
||||
# 如果有单价,单价除以倍数
|
||||
new_price = price / multiplier if price else 0
|
||||
|
||||
logger.info(f"特殊条码处理: {barcode}, 数量: {quantity} -> {new_quantity}, 单价: {price} -> {new_price}, 单位: {unit} -> {target_unit}")
|
||||
|
||||
result['quantity'] = new_quantity
|
||||
result['price'] = new_price
|
||||
result['unit'] = target_unit
|
||||
return result
|
||||
|
||||
# 没有规格信息,无法进行单位转换
|
||||
if not specification:
|
||||
return result
|
||||
|
||||
# 解析规格信息
|
||||
level1, level2, level3 = self.parse_specification(specification)
|
||||
|
||||
# "件"单位处理
|
||||
if unit in ['件']:
|
||||
# 计算包装数量(二级*三级,如果无三级则仅二级)
|
||||
packaging_count = level2 * (level3 or 1)
|
||||
|
||||
# 数量×包装数量
|
||||
new_quantity = quantity * packaging_count
|
||||
|
||||
# 单价÷包装数量
|
||||
new_price = price / packaging_count if price else 0
|
||||
|
||||
logger.info(f"件单位处理: 数量: {quantity} -> {new_quantity}, 单价: {price} -> {new_price}, 单位: 件 -> 瓶")
|
||||
|
||||
result['quantity'] = new_quantity
|
||||
result['price'] = new_price
|
||||
result['unit'] = '瓶'
|
||||
return result
|
||||
|
||||
# "箱"单位处理 - 与"件"单位处理相同
|
||||
if unit in ['箱']:
|
||||
# 计算包装数量
|
||||
packaging_count = level2 * (level3 or 1)
|
||||
|
||||
# 数量×包装数量
|
||||
new_quantity = quantity * packaging_count
|
||||
|
||||
# 单价÷包装数量
|
||||
new_price = price / packaging_count if price else 0
|
||||
|
||||
logger.info(f"箱单位处理: 数量: {quantity} -> {new_quantity}, 单价: {price} -> {new_price}, 单位: 箱 -> 瓶")
|
||||
|
||||
result['quantity'] = new_quantity
|
||||
result['price'] = new_price
|
||||
result['unit'] = '瓶'
|
||||
return result
|
||||
|
||||
# "提"和"盒"单位处理
|
||||
if unit in ['提', '盒']:
|
||||
# 如果是三级规格,按件处理
|
||||
if level3 is not None:
|
||||
# 计算包装数量
|
||||
packaging_count = level2 * level3
|
||||
|
||||
# 数量×包装数量
|
||||
new_quantity = quantity * packaging_count
|
||||
|
||||
# 单价÷包装数量
|
||||
new_price = price / packaging_count if price else 0
|
||||
|
||||
logger.info(f"提/盒单位(三级规格)处理: 数量: {quantity} -> {new_quantity}, 单价: {price} -> {new_price}, 单位: {unit} -> 瓶")
|
||||
|
||||
result['quantity'] = new_quantity
|
||||
result['price'] = new_price
|
||||
result['unit'] = '瓶'
|
||||
else:
|
||||
# 如果是二级规格,保持不变
|
||||
logger.info(f"提/盒单位(二级规格)处理: 保持原样 数量: {quantity}, 单价: {price}, 单位: {unit}")
|
||||
|
||||
return result
|
||||
|
||||
# 其他单位保持不变
|
||||
logger.info(f"其他单位处理: 保持原样 数量: {quantity}, 单价: {price}, 单位: {unit}")
|
||||
return result
|
||||
+92
-25
@@ -294,33 +294,100 @@ class ExcelProcessor:
|
||||
output_workbook = xlcopy(template_workbook)
|
||||
output_sheet = output_workbook.get_sheet(0)
|
||||
|
||||
# 填充商品信息
|
||||
start_row = 1 # 从第2行开始填充数据(索引从0开始)
|
||||
# 先对产品按条码分组,区分正常商品和赠品
|
||||
barcode_groups = {}
|
||||
|
||||
for i, product in enumerate(products):
|
||||
row = start_row + i
|
||||
# 遍历所有产品,按条码分组
|
||||
logger.info(f"开始处理{len(products)} 个产品信息")
|
||||
for product in products:
|
||||
barcode = product.get('barcode', '')
|
||||
if not barcode:
|
||||
logger.warning(f"跳过无条码商品")
|
||||
continue
|
||||
|
||||
# 序号
|
||||
output_sheet.write(row, 0, i + 1)
|
||||
# 商品编码(条码)
|
||||
output_sheet.write(row, 1, product['barcode'])
|
||||
# 商品名称
|
||||
output_sheet.write(row, 2, product['name'])
|
||||
# 规格
|
||||
output_sheet.write(row, 3, product['specification'])
|
||||
# 单位
|
||||
output_sheet.write(row, 4, product['unit'])
|
||||
# 单价
|
||||
output_sheet.write(row, 5, product['price'])
|
||||
# 采购数量
|
||||
output_sheet.write(row, 6, product['quantity'])
|
||||
# 采购金额(单价 × 数量)
|
||||
amount = product['price'] * product['quantity']
|
||||
output_sheet.write(row, 7, amount)
|
||||
# 税率
|
||||
output_sheet.write(row, 8, 0)
|
||||
# 赠送量(默认为0)
|
||||
output_sheet.write(row, 9, 0)
|
||||
# 获取数量和单价
|
||||
quantity = product.get('quantity', 0)
|
||||
price = product.get('price', 0)
|
||||
|
||||
# 判断是否为赠品(价格为0)
|
||||
is_gift = price == 0
|
||||
|
||||
logger.info(f"处理商品: 条码={barcode}, 数量={quantity}, 单价={price}, 是否赠品={is_gift}")
|
||||
|
||||
if barcode not in barcode_groups:
|
||||
barcode_groups[barcode] = {
|
||||
'normal': None, # 正常商品信息
|
||||
'gift_quantity': 0 # 赠品数量
|
||||
}
|
||||
|
||||
if is_gift:
|
||||
# 是赠品,累加赠品数量
|
||||
barcode_groups[barcode]['gift_quantity'] += quantity
|
||||
logger.info(f"发现赠品:条码{barcode}, 数量={quantity}")
|
||||
else:
|
||||
# 是正常商品
|
||||
if barcode_groups[barcode]['normal'] is None:
|
||||
barcode_groups[barcode]['normal'] = {
|
||||
'product': product,
|
||||
'quantity': quantity,
|
||||
'price': price
|
||||
}
|
||||
logger.info(f"发现正常商品:条码{barcode}, 数量={quantity}, 单价={price}")
|
||||
else:
|
||||
# 如果有多个正常商品记录,累加数量
|
||||
barcode_groups[barcode]['normal']['quantity'] += quantity
|
||||
logger.info(f"累加正常商品数量:条码{barcode}, 新增={quantity}, 累计={barcode_groups[barcode]['normal']['quantity']}")
|
||||
|
||||
# 如果单价不同,取平均值
|
||||
if price != barcode_groups[barcode]['normal']['price']:
|
||||
avg_price = (barcode_groups[barcode]['normal']['price'] + price) / 2
|
||||
barcode_groups[barcode]['normal']['price'] = avg_price
|
||||
logger.info(f"调整单价(取平均值):条码{barcode}, 原价={barcode_groups[barcode]['normal']['price']}, 新价={price}, 平均={avg_price}")
|
||||
|
||||
# 输出调试信息
|
||||
logger.info(f"分组后共{len(barcode_groups)} 个不同条码的商品")
|
||||
for barcode, group in barcode_groups.items():
|
||||
if group['normal'] is not None:
|
||||
logger.info(f"条码 {barcode} 处理结果:正常商品数量{group['normal']['quantity']},单价{group['normal']['price']},赠品数量{group['gift_quantity']}")
|
||||
else:
|
||||
logger.info(f"条码 {barcode} 处理结果:只有赠品,数量={group['gift_quantity']}")
|
||||
|
||||
# 准备填充数据
|
||||
row_index = 1 # 从第2行开始填充(索引从0开始)
|
||||
|
||||
for barcode, group in barcode_groups.items():
|
||||
# 1. 列B(1): 条码(必填)
|
||||
output_sheet.write(row_index, 1, barcode)
|
||||
|
||||
if group['normal'] is not None:
|
||||
# 有正常商品
|
||||
product = group['normal']['product']
|
||||
|
||||
# 2. 列C(2): 采购量(必填) 使用正常商品的采购量
|
||||
normal_quantity = group['normal']['quantity']
|
||||
output_sheet.write(row_index, 2, normal_quantity)
|
||||
|
||||
# 3. 列D(3): 赠送量 - 添加赠品数量
|
||||
if group['gift_quantity'] > 0:
|
||||
output_sheet.write(row_index, 3, group['gift_quantity'])
|
||||
logger.info(f"条码 {barcode} 填充:采购量={normal_quantity},赠品数量{group['gift_quantity']}")
|
||||
|
||||
# 4. 列E(4): 采购单价(必填)
|
||||
purchase_price = group['normal']['price']
|
||||
style = xlwt.XFStyle()
|
||||
style.num_format_str = '0.0000'
|
||||
output_sheet.write(row_index, 4, round(purchase_price, 4), style)
|
||||
else:
|
||||
# 只有赠品,没有正常商品
|
||||
# 采购量填0,赠送量填赠品数量
|
||||
output_sheet.write(row_index, 2, 0) # 采购量为0
|
||||
output_sheet.write(row_index, 3, group['gift_quantity']) # 赠送量
|
||||
output_sheet.write(row_index, 4, 0) # 单价为0
|
||||
|
||||
logger.info(f"条码 {barcode} 填充:仅有赠品,采购量=0,赠品数量={group['gift_quantity']}")
|
||||
|
||||
# 移到下一行
|
||||
row_index += 1
|
||||
|
||||
# 保存文件
|
||||
output_workbook.save(output_file_path)
|
||||
|
||||
Reference in New Issue
Block a user