feat(entitlement): execute_product 接权益生效
- 资源模块 execute_product_service 返回 entitlement(账号:有效期+工作空间配额; 存储:容量GB) - 产品层 execute_product 调 _grant_subscription 写 product_subscription(订阅+配额,幂等)
This commit is contained in:
parent
d423f4ffd2
commit
622dec8495
@ -1332,7 +1332,7 @@ class ProductManager:
|
|||||||
|
|
||||||
async def execute_product(self, product_id=None, product_code=None,
|
async def execute_product(self, product_id=None, product_code=None,
|
||||||
request_data=None, user_id=None, user_org_id=None):
|
request_data=None, user_id=None, user_org_id=None):
|
||||||
"""执行产品服务(通过资源模块接口)。"""
|
"""执行产品服务:资源侧执行 + 订阅/配额权益生效。"""
|
||||||
iface, product, err = await self._get_product_interface(
|
iface, product, err = await self._get_product_interface(
|
||||||
product_id, product_code)
|
product_id, product_code)
|
||||||
if err:
|
if err:
|
||||||
@ -1343,6 +1343,8 @@ class ProductManager:
|
|||||||
return {'success': False, 'message': '资源模块未实现 execute_product_service',
|
return {'success': False, 'message': '资源模块未实现 execute_product_service',
|
||||||
'status': 'FAILED'}
|
'status': 'FAILED'}
|
||||||
|
|
||||||
|
product = product or {}
|
||||||
|
|
||||||
ref_id, err = self._get_ref_id(product)
|
ref_id, err = self._get_ref_id(product)
|
||||||
if err:
|
if err:
|
||||||
return {'success': False, 'message': err, 'status': 'FAILED'}
|
return {'success': False, 'message': err, 'status': 'FAILED'}
|
||||||
@ -1353,7 +1355,67 @@ class ProductManager:
|
|||||||
if not user_org_id:
|
if not user_org_id:
|
||||||
user_org_id = self._get_current_org_id()
|
user_org_id = self._get_current_org_id()
|
||||||
|
|
||||||
return await fn(ref_id, user_id, user_org_id, request_data or {})
|
result = await fn(ref_id, user_id, user_org_id, request_data or {})
|
||||||
|
if not isinstance(result, dict) or not result.get('success'):
|
||||||
|
return result
|
||||||
|
|
||||||
|
# 权益生效:资源模块返回 entitlement 时,写 product_subscription(订阅/配额)
|
||||||
|
ent = result.get('entitlement')
|
||||||
|
if ent:
|
||||||
|
try:
|
||||||
|
result['subscription_id'] = await self._grant_subscription(
|
||||||
|
product, ent, user_id, user_org_id)
|
||||||
|
except Exception as e:
|
||||||
|
result['message'] = (result.get('message', '') or '') + f';订阅写入失败: {e}'
|
||||||
|
return result
|
||||||
|
|
||||||
|
async def _grant_subscription(self, product, entitlement, user_id, user_org_id):
|
||||||
|
"""写 product_subscription:订阅有效期 + 配额(账号工作空间数/存储容量GB)。
|
||||||
|
|
||||||
|
幂等:同一产品+机构已有活跃订阅则更新有效期与配额,不重复建。
|
||||||
|
"""
|
||||||
|
dbname = self._get_dbname()
|
||||||
|
now = time.strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
today = datetime.date.today()
|
||||||
|
days = int(entitlement.get('duration_days', 0) or 0)
|
||||||
|
end_date = (today + datetime.timedelta(days=days)).isoformat() if days else today.isoformat()
|
||||||
|
|
||||||
|
quota_total = 0.0
|
||||||
|
quota_unit = entitlement.get('quota_unit', '')
|
||||||
|
if entitlement.get('workspace_max'):
|
||||||
|
quota_total = float(entitlement['workspace_max'])
|
||||||
|
quota_unit = quota_unit or 'workspace'
|
||||||
|
elif entitlement.get('storage_gb'):
|
||||||
|
quota_total = float(entitlement['storage_gb'])
|
||||||
|
quota_unit = quota_unit or 'GB'
|
||||||
|
elif entitlement.get('workspace_gb'):
|
||||||
|
quota_total = float(entitlement['workspace_gb'])
|
||||||
|
quota_unit = quota_unit or 'GB'
|
||||||
|
|
||||||
|
sub_id = getID()
|
||||||
|
async with DBPools().sqlorContext(dbname) as sor:
|
||||||
|
existing = await sor.sqlExe(
|
||||||
|
"SELECT id FROM product_subscription WHERE product_id=${pid}$ "
|
||||||
|
"AND user_org_id=${org}$ AND status='1' LIMIT 1",
|
||||||
|
{'pid': product.get('id'), 'org': user_org_id})
|
||||||
|
if existing:
|
||||||
|
sub_id = existing[0].id
|
||||||
|
await sor.U('product_subscription', {
|
||||||
|
'id': sub_id, 'start_date': today.isoformat(),
|
||||||
|
'end_date': end_date, 'quota_total': quota_total,
|
||||||
|
'quota_unit': quota_unit, 'updated_at': now})
|
||||||
|
else:
|
||||||
|
await sor.C('product_subscription', {
|
||||||
|
'id': sub_id, 'product_id': product.get('id'),
|
||||||
|
'user_id': user_id, 'user_org_id': user_org_id,
|
||||||
|
'subscription_type': '1', 'status': '1',
|
||||||
|
'start_date': today.isoformat(), 'end_date': end_date,
|
||||||
|
'quota_total': quota_total, 'quota_used': 0,
|
||||||
|
'quota_unit': quota_unit, 'overflow_mode': '1', 'overflow_rate': 0,
|
||||||
|
'purchase_price': float(product.get('price', 0) or 0),
|
||||||
|
'purchase_currency': product.get('currency', 'CNY'),
|
||||||
|
'created_at': now, 'updated_at': now})
|
||||||
|
return sub_id
|
||||||
|
|
||||||
async def execute_product_stream(self, product_id=None, product_code=None,
|
async def execute_product_stream(self, product_id=None, product_code=None,
|
||||||
request_data=None, user_id=None,
|
request_data=None, user_id=None,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user