diff --git a/pricing/pricing.py b/pricing/pricing.py index bb9bfd4..c05e567 100644 --- a/pricing/pricing.py +++ b/pricing/pricing.py @@ -525,7 +525,10 @@ order by b.enabled_date desc""" @staticmethod def get_pricing_from_ymalstr(config_data, yamlstr): """ - yamlstr是从 + 解析定价YAML并计算费用。 + 支持两种格式: + 1. 旧格式:formula 字段(eval计算) + 2. 新格式:price_factors + unit_prices + unit(自动计算) """ if config_data is None: e = Exception(f'config_data is None, {yamlstr=}') @@ -545,19 +548,34 @@ order by b.enabled_date desc""" if not d.pricings: exception(f'{d} has not "pricings"') raise Exception(f'定价定义中没有pricing数据') + + # 单位映射表 + unit_values = d.get('unit_values', {'百万': 1000000, '秒': 1, '千': 1000, '次': 1, '张': 1, '毫秒': 0.001}) + ret_items = [] for i, p in enumerate(d.pricings): - if not p.formula: - debug(f'无公式:{p=}') + # 跳过需要人工审核的记录 + if p.get('_NEEDS_MANUAL_REVIEW'): + debug(f'跳过需要人工审核的定价项: {i}') continue + + # 判断是旧格式还是新格式 + is_new_format = p.get('price_factors') is not None and p.get('unit_prices') is not None + is_old_format = p.get('formula') is not None + + if not is_new_format and not is_old_format: + debug(f'无公式也无price_factors:{p=}') + continue + p_ok = True - times = 1 - unit = 1 ns = DictObject(**config_data) - for k,spec_value in p.items(): + + # 检查过滤条件(排除定价计算字段) + skip_keys = {'formula', 'price_factors', 'unit_prices', 'unit', 'min_amount', 'filters', 'pricing_type'} + for k, spec_value in p.items(): if spec_value is None: continue - if k == 'formula': + if k in skip_keys: continue f = d.fields.get(k) if not f: @@ -565,8 +583,6 @@ order by b.enabled_date desc""" exception(f'{e}') raise Exception(e) data_value = config_data.get(k) - # p[f'old_{k}'] = data_value - # p[f'mapping_{k}'] = data_mapping(d, k, data_value) #需要mapping的数据转换 data_value = data_mapping(d, k, data_value) if data_value is None: if 'default' in f.keys(): @@ -578,28 +594,112 @@ order by b.enabled_date desc""" try: flg = check_value(f, spec_value, data_value) if not flg: - # 条件不满足 - # debug(f'条件不满足:{p=},{spec_value=}, {data_value=}, {k=}') p_ok = False break except Exception as e: msg = f'{p=},{f}: {spec_value=}, {data_value=}' exception(f'{e}:{msg}') break - if p_ok and p.formula: - np = p.copy() + + # 检查 filters 区间条件(新格式) + if p_ok and is_new_format and 'filters' in p: + # filters 是多个区间选项,只要有一个匹配就行 + filter_matched = False + for filter_item in p['filters']: + item_ok = True + for fk, fv in filter_item.items(): + if fk == 'unit_prices': + continue + f = d.fields.get(fk) + if not f: + continue + data_value = config_data.get(fk) + data_value = data_mapping(d, fk, data_value) + if data_value is None: + continue + try: + flg = check_value(f, fv, data_value) + if not flg: + item_ok = False + break + except Exception as e: + debug(f'filter check error: {e}') + item_ok = False + break + if item_ok: + filter_matched = True + break + if not filter_matched: + p_ok = False + + if not p_ok: + info(f'{config_data=}, {p=}, mismatched') + continue + + np = p.copy() + np.data = config_data + + if is_new_format: + # 新格式:price_factors + unit_prices + unit + factor_name = p['price_factors'] + unit_price = p['unit_prices'] + unit_str = p.get('unit', '次') + + # 处理 filters 中的区间定价(查找匹配的 unit_prices) + if 'filters' in p: + for filter_item in p['filters']: + for fk, fv in filter_item.items(): + if fk == 'unit_prices': + continue + f = d.fields.get(fk) + if not f: + continue + data_value = config_data.get(fk) + data_value = data_mapping(d, fk, data_value) + if data_value is None: + continue + try: + flg = check_value(f, fv, data_value) + if flg and 'unit_prices' in filter_item: + unit_price = filter_item['unit_prices'] + except: + pass + + # 获取 usage 值 + if factor_name == 'flat': + # 固定费用 + usage_value = 1 + else: + usage_value = config_data.get(factor_name) + if usage_value is None: + debug(f'新格式:config_data中缺少{factor_name}') + continue + usage_value = float(usage_value) + + # 获取单位值 + unit_val = unit_values.get(unit_str, 1) + if isinstance(unit_val, str): + unit_val = float(unit_val) + + # 计算金额 + amount = unit_price * usage_value / unit_val + + # 应用 min_amount + min_amount = p.get('min_amount', 0) + if min_amount and amount < min_amount: + amount = min_amount + + np.amount = amount + ret_items.append(np) + + elif is_old_format: + # 旧格式:formula formula = p.formula - if not formula: - e = f'{p} not formula found' - exception(e) - raise Exception(e) debug(f'{formula=}, {ns=}, {p=}, {d.fields=}') - np.data = config_data env_data = DictObject(config_data) np.amount = eval(formula, env_data) ret_items.append(np) - else: - info(f'{config_data=}, {p=}, {d.model_mappings=}, mismatched') + if len(ret_items) == 0: e = f'{config_data=}{yamlstr=}没有找到合适的定价' exception(e) diff --git a/scripts/__pycache__/load_path.cpython-310.pyc b/scripts/__pycache__/load_path.cpython-310.pyc index 4cd5477..1cfd348 100644 Binary files a/scripts/__pycache__/load_path.cpython-310.pyc and b/scripts/__pycache__/load_path.cpython-310.pyc differ