diff --git a/product_management/core.py b/product_management/core.py index fdf36c4..d8ee48f 100644 --- a/product_management/core.py +++ b/product_management/core.py @@ -1097,13 +1097,15 @@ class ProductManager: parent_category_id, user_id): """Import sub-categories and products from a resource module. - Dynamically imports the resource module and calls its - load_product_category_product(parent_category_id) function, - which is responsible for both reading source data and writing - sub-categories + products under the given parent_category_id. + 1. Calls resource module's load_product_category_product() to get standardized data + 2. For categories: skip if exists (by name+parent_id+org_id), else create + 3. For products: update if exists (by resource_ref_id+org_id), else create """ import importlib + import time + from appPublic.uniqueID import getID + # Step 1: Get standardized data from resource module try: mod = importlib.import_module(f'{resource_module}.init') load_fn = getattr(mod, 'load_product_category_product', None) @@ -1118,10 +1120,115 @@ class ProductManager: except Exception as e: return {'success': False, 'error': f'调用 {resource_module}.load_product_category_product() 失败: {e}'} - if not result: - return {'success': False, 'error': f'资源模块 "{resource_module}" 未返回导入数据'} + if not result or not result.get('success'): + return {'success': False, 'error': result.get('error', '资源模块未返回有效数据') if result else '资源模块未返回数据'} - return result + categories = result.get('categories', []) + products = result.get('products', []) + + if not categories and not products: + return {'success': False, 'error': '资源模块返回数据为空'} + + dbname = self._get_dbname() + now = time.strftime('%Y-%m-%d %H:%M:%S') + source_to_id = {} # source_id -> product_category.id + created_cats = 0 + skipped_cats = 0 + created_prods = 0 + updated_prods = 0 + + async with DBPools().sqlorContext(dbname) as sor: + # Step 2: Process categories — skip existing, create new + for cat in categories: + existing = await sor.sqlExe( + """SELECT id FROM product_category + WHERE name = ${name}$ AND parent_id = ${parent_id}$ AND org_id = ${org_id}$""", + {'name': cat['name'], 'parent_id': parent_category_id, 'org_id': org_id} + ) + if existing: + source_to_id[cat['source_id']] = existing[0].id + skipped_cats += 1 + continue + + new_id = getID() + source_to_id[cat['source_id']] = new_id + await sor.C('product_category', { + 'id': new_id, + 'parent_id': parent_category_id, + 'name': cat['name'], + 'description': cat.get('description', ''), + 'has_product': '1', + 'product_type': cat.get('product_type', ''), + 'product_type_title': cat.get('product_type_title', ''), + 'sort_order': str(cat.get('sort_order', 0)), + 'icon': '', + 'status': '1', + 'resource_module': resource_module, + 'org_id': org_id, + 'created_by': user_id, + 'created_at': now, + 'updated_at': now + }) + created_cats += 1 + + # Step 3: Process products — update existing, create new + for prod in products: + target_cat_id = source_to_id.get(prod.get('source_category_id')) + if not target_cat_id: + continue + + resource_ref_id = prod.get('resource_ref_id', '') + + # Check if product already exists by resource_ref_id + org_id + existing_prod = None + if resource_ref_id: + existing_prod = await sor.sqlExe( + """SELECT id FROM product + WHERE resource_ref_id = ${ref_id}$ AND org_id = ${org_id}$""", + {'ref_id': resource_ref_id, 'org_id': org_id} + ) + + if existing_prod: + # Update existing product + await sor.U('product', { + 'id': existing_prod[0].id, + 'product_name': prod.get('product_name', ''), + 'product_code': prod.get('product_code', ''), + 'product_type': prod.get('product_type', ''), + 'brief_intro': prod.get('brief_intro', ''), + 'category_id': target_cat_id, + 'sort_order': str(prod.get('sort_order', 0)), + 'updated_at': now + }) + updated_prods += 1 + else: + # Create new product + prod_id = getID() + await sor.C('product', { + 'id': prod_id, + 'category_id': target_cat_id, + 'product_code': prod.get('product_code', ''), + 'resource_ref_id': resource_ref_id, + 'product_name': prod.get('product_name', ''), + 'product_type': prod.get('product_type', ''), + 'brief_intro': prod.get('brief_intro', ''), + 'status': '1', + 'price_type': '1', + 'price': '0', + 'currency': 'CNY', + 'sort_order': str(prod.get('sort_order', 0)), + 'org_id': org_id, + 'created_by': user_id, + 'created_at': now, + 'updated_at': now + }) + created_prods += 1 + + return { + 'success': True, + 'message': f'导入完成: 新增 {created_cats} 个类别, {created_prods} 个产品; ' + f'跳过 {skipped_cats} 个已有类别; 更新 {updated_prods} 个已有产品' + } # ─── Resource Module Interface Dispatcher ───