qrpa 1.1.35__tar.gz → 1.1.36__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of qrpa might be problematic. Click here for more details.

Files changed (40) hide show
  1. {qrpa-1.1.35 → qrpa-1.1.36}/PKG-INFO +1 -1
  2. {qrpa-1.1.35 → qrpa-1.1.36}/pyproject.toml +1 -1
  3. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/mysql_module/new_product_analysis_model.py +7 -1
  4. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/shein_lib.py +253 -2
  5. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa.egg-info/PKG-INFO +1 -1
  6. {qrpa-1.1.35 → qrpa-1.1.36}/README.md +0 -0
  7. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/RateLimitedSender.py +0 -0
  8. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/__init__.py +0 -0
  9. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/db_migrator.py +0 -0
  10. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/feishu_bot_app.py +0 -0
  11. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/feishu_client.py +0 -0
  12. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/feishu_logic.py +0 -0
  13. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/fun_base.py +0 -0
  14. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/fun_excel.py +0 -0
  15. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/fun_file.py +0 -0
  16. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/fun_web.py +0 -0
  17. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/fun_win.py +0 -0
  18. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/mysql_module/__init__.py +0 -0
  19. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/mysql_module/shein_ledger_model.py +0 -0
  20. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/mysql_module/shein_product_model.py +0 -0
  21. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/mysql_module/shein_return_order_model.py +0 -0
  22. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/mysql_module/shein_store_model.py +0 -0
  23. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/shein_daily_report_model.py +0 -0
  24. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/shein_excel.py +0 -0
  25. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/shein_mysql.py +0 -0
  26. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/shein_sqlite.py +0 -0
  27. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/shein_ziniao.py +0 -0
  28. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/temu_chrome.py +0 -0
  29. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/temu_excel.py +0 -0
  30. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/temu_lib.py +0 -0
  31. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/time_utils.py +0 -0
  32. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/time_utils_example.py +0 -0
  33. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa/wxwork.py +0 -0
  34. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa.egg-info/SOURCES.txt +0 -0
  35. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa.egg-info/dependency_links.txt +0 -0
  36. {qrpa-1.1.35 → qrpa-1.1.36}/qrpa.egg-info/top_level.txt +0 -0
  37. {qrpa-1.1.35 → qrpa-1.1.36}/setup.cfg +0 -0
  38. {qrpa-1.1.35 → qrpa-1.1.36}/setup.py +0 -0
  39. {qrpa-1.1.35 → qrpa-1.1.36}/tests/test_db_migrator.py +0 -0
  40. {qrpa-1.1.35 → qrpa-1.1.36}/tests/test_wxwork.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrpa
3
- Version: 1.1.35
3
+ Version: 1.1.36
4
4
  Summary: qsir's rpa library
5
5
  Author: QSir
6
6
  Author-email: QSir <1171725650@qq.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "qrpa"
7
- version = "1.1.35"
7
+ version = "1.1.36"
8
8
  description = "qsir's rpa library"
9
9
  authors = [{ name = "QSir", email = "1171725650@qq.com" }]
10
10
  readme = "README.md"
@@ -236,7 +236,13 @@ class NewProductAnalysisManager:
236
236
  prom_detail = prom.get('promDetail', [])
237
237
 
238
238
  # 根据promId长度判断取哪些字段
239
- if len(str(prom_id)) > 6 and prom_detail:
239
+ if len(str(prom_id)) >= 11 and prom_detail:
240
+ # 营销工具:取第一个detail的数据
241
+ detail = prom_detail if prom_detail else {}
242
+ prom_info['attend_num_sum'] = detail.get('act_stock_num')
243
+ prom_info['supply_price'] = detail.get('sku_price')
244
+ prom_info['product_act_price'] = detail.get('act_sku_price')
245
+ elif len(str(prom_id)) >= 8 and prom_detail:
240
246
  # 营销工具:取第一个detail的数据
241
247
  detail = prom_detail[0] if prom_detail else {}
242
248
  prom_info['attend_num_sum'] = detail.get('attend_num_sum')
@@ -1236,7 +1236,10 @@ class SheinLib:
1236
1236
  for prom_inf_ing in skc_item['promCampaign'].get('promInfIng') or []:
1237
1237
  prom_id = prom_inf_ing['promId']
1238
1238
  log('prom_id:', prom_id, len(prom_id))
1239
- if len(prom_id) >= 6:
1239
+ if len(prom_id) >= 11:
1240
+ # 托管活动
1241
+ prom_inf_ing['promDetail'] = self.get_skc_activity_price_info(skc, prom_id)
1242
+ elif len(prom_id) >= 8:
1240
1243
  # 营销工具
1241
1244
  prom_inf_ing['promDetail'] = self.query_goods_detail(prom_id)
1242
1245
  else:
@@ -1246,7 +1249,9 @@ class SheinLib:
1246
1249
  for prom_inf_ready in skc_item['promCampaign'].get('promInfReady') or []:
1247
1250
  prom_id = prom_inf_ready['promId']
1248
1251
  log('prom_id:', prom_id, len(prom_id))
1249
- if len(prom_id) >= 6:
1252
+ if len(prom_id) >= 11:
1253
+ prom_inf_ready['promDetail'] = self.get_skc_activity_price_info(skc, prom_id)
1254
+ elif len(prom_id) >= 8:
1250
1255
  prom_inf_ready['promDetail'] = self.query_goods_detail(prom_id)
1251
1256
  else:
1252
1257
  prom_inf_ready['promDetail'] = self.get_partake_activity_detail(prom_id, skc)
@@ -2373,6 +2378,7 @@ class SheinLib:
2373
2378
  list_item += response_text['info']['data']
2374
2379
  time.sleep(0.1)
2375
2380
 
2381
+ log(list_item)
2376
2382
  write_dict_to_file(cache_file, list_item)
2377
2383
  return list_item
2378
2384
 
@@ -2398,6 +2404,7 @@ class SheinLib:
2398
2404
  raise send_exception(json.dumps(response_text, ensure_ascii=False))
2399
2405
  list_item = response_text['info']['data']
2400
2406
 
2407
+ log(list_item)
2401
2408
  write_dict_to_file(cache_file, list_item)
2402
2409
  return list_item
2403
2410
 
@@ -3930,3 +3937,247 @@ class SheinLib:
3930
3937
  log('临时下载文件已清理')
3931
3938
 
3932
3939
  return output_file_path
3940
+
3941
+ def query_hosting_info_list(self):
3942
+ """
3943
+ 查询店铺活动托管规则列表
3944
+
3945
+ Returns:
3946
+ list: 托管规则列表,每个元素包含:
3947
+ - hosting_id: 托管规则ID
3948
+ - scene_type: 场景类型
3949
+ - state: 状态
3950
+ - hosting_name: 托管规则名称
3951
+ - hosting_tools_id: 托管工具ID
3952
+ - hosting_tools_state: 托管工具状态
3953
+ - time_zone: 时区
3954
+ - create_user: 创建用户
3955
+ - last_update_user: 最后更新用户
3956
+ - insert_time: 创建时间
3957
+ - last_update_time: 最后更新时间
3958
+ - exist_act_goods: 是否存在活动商品
3959
+ """
3960
+ log(f'正在获取 {self.store_name} 店铺活动托管规则列表')
3961
+
3962
+ cache_file = f'{self.config.auto_dir}/shein/cache/hosting_info_list_{self.store_username}_{TimeUtils.today_date()}.json'
3963
+ hosting_list = read_dict_from_file_ex(cache_file, self.store_username, 3600 * 8)
3964
+ if len(hosting_list) > 0:
3965
+ log('返回缓存数据')
3966
+ return hosting_list
3967
+
3968
+ url = "https://sso.geiwohuo.com/mrs-api-prefix/promotion/hosting/query_hosting_info_list"
3969
+ payload = {}
3970
+
3971
+ response_text = fetch(self.web_page, url, payload)
3972
+ error_code = response_text.get('code')
3973
+ if str(error_code) != '0':
3974
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
3975
+
3976
+ hosting_list = response_text.get('info', [])
3977
+ log(f'获取到 {len(hosting_list)} 条托管规则')
3978
+
3979
+ write_dict_to_file_ex(cache_file, {self.store_username: hosting_list}, [self.store_username])
3980
+
3981
+ return hosting_list
3982
+
3983
+ def query_hosting_activity_goods(self, hosting_id, goods_states=None):
3984
+ """
3985
+ 查询托管活动参与的商品
3986
+
3987
+ Args:
3988
+ hosting_id: 托管规则ID
3989
+ goods_states: 商品状态列表,默认为[1](在售)
3990
+
3991
+ Returns:
3992
+ list: 参与托管活动的商品列表,每个元素包含:
3993
+ - goods_state: 商品状态
3994
+ - skc_info_list: SKC信息列表
3995
+ - skc_id: SKC ID
3996
+ - skc_name: SKC名称
3997
+ - goods_name: 商品名称
3998
+ - image_url: 图片URL
3999
+ - act_stock_num: 活动库存数量
4000
+ - act_sales_num: 活动销量
4001
+ - activity_info: 活动信息
4002
+ - sku_info_list: SKU信息列表
4003
+ """
4004
+ if goods_states is None:
4005
+ goods_states = [1]
4006
+
4007
+ log(f'正在获取 {self.store_name} 托管活动商品列表 hosting_id={hosting_id}')
4008
+
4009
+ cache_file = f'{self.config.auto_dir}/shein/cache/hosting_activity_goods_{self.store_username}_{hosting_id}_{TimeUtils.today_date()}.json'
4010
+ goods_list = read_dict_from_file_ex(cache_file, self.store_username, 3600 * 8)
4011
+ if len(goods_list) > 0:
4012
+ log('返回缓存数据')
4013
+ return goods_list
4014
+
4015
+ page_num = 1
4016
+ page_size = 100
4017
+
4018
+ url = "https://sso.geiwohuo.com/mrs-api-prefix/promotion/hosting/query_hosting_activity_goods"
4019
+ payload = {
4020
+ "goods_states": goods_states,
4021
+ "hosting_id" : str(hosting_id),
4022
+ "page_num" : page_num,
4023
+ "page_size" : page_size
4024
+ }
4025
+
4026
+ response_text = fetch(self.web_page, url, payload)
4027
+ error_code = response_text.get('code')
4028
+ if str(error_code) != '0':
4029
+ raise send_exception(json.dumps(response_text, ensure_ascii=False))
4030
+
4031
+ goods_list = response_text.get('info', [])
4032
+ if not goods_list:
4033
+ log('未获取到商品数据')
4034
+ return []
4035
+
4036
+ # 获取第一页数据
4037
+ first_item = goods_list[0] if goods_list else {}
4038
+ skc_info_list = first_item.get('skc_info_list', {})
4039
+ all_data = skc_info_list.get('data', [])
4040
+ meta = skc_info_list.get('meta', {})
4041
+ total = meta.get('count', 0)
4042
+
4043
+ log(f'第1页获取到 {len(all_data)} 条商品,总数: {total}')
4044
+
4045
+ # 如果有多页,继续获取
4046
+ if total > page_size:
4047
+ totalPage = math.ceil(total / page_size)
4048
+ for page in range(2, totalPage + 1):
4049
+ log(f'获取托管活动商品列表 第{page}/{totalPage}页')
4050
+ payload['page_num'] = page
4051
+ response_text = fetch(self.web_page, url, payload)
4052
+ error_code = response_text.get('code')
4053
+ if str(error_code) != '0':
4054
+ log(f'获取第{page}页失败: {response_text}')
4055
+ continue
4056
+
4057
+ page_goods_list = response_text.get('info', [])
4058
+ if page_goods_list:
4059
+ page_data = page_goods_list[0].get('skc_info_list', {}).get('data', [])
4060
+ all_data.extend(page_data)
4061
+ log(f'第{page}页获取到 {len(page_data)} 条商品')
4062
+
4063
+ time.sleep(0.1)
4064
+
4065
+ log(f'总共获取到 {len(all_data)} 条商品')
4066
+
4067
+ # 保存缓存
4068
+ write_dict_to_file_ex(cache_file, {self.store_username: all_data}, [self.store_username])
4069
+
4070
+ return all_data
4071
+
4072
+ def get_skc_activity_price_info(self, skc, activity_id):
4073
+ """
4074
+ 根据SKC和活动ID获取供货价、活动价和活动库存
4075
+
4076
+ Args:
4077
+ skc: SKC名称
4078
+ activity_id: 活动ID(可以是字符串或整数)
4079
+
4080
+ Returns:
4081
+ dict: 包含以下键值的字典,如果未找到则返回None:
4082
+ - sku_price: SKU供货价(取第一个SKU的价格)
4083
+ - act_sku_price: SKU活动价(取第一个SKU的活动价)
4084
+ - act_stock_num: 活动库存数量
4085
+ - skc_name: SKC名称
4086
+ - goods_name: 商品名称
4087
+ - activity_id: 活动ID
4088
+ - currency: 币种
4089
+ - image_url: 商品图片
4090
+ """
4091
+ log(f'获取SKC活动价格信息: skc={skc}, activity_id={activity_id}')
4092
+
4093
+ # 转换activity_id为整数进行比较
4094
+ try:
4095
+ target_activity_id = int(activity_id)
4096
+ except (ValueError, TypeError):
4097
+ log(f'无效的activity_id: {activity_id}')
4098
+ return None
4099
+
4100
+ # 缓存文件,使用skc和activity_id作为缓存key
4101
+ cache_file = f'{self.config.auto_dir}/shein/cache/skc_activity_price_{self.store_username}_{skc}_{activity_id}_{TimeUtils.today_date()}.json'
4102
+ cached_data = read_dict_from_file(cache_file, 3600 * 8)
4103
+ if cached_data:
4104
+ log('返回缓存的价格信息')
4105
+ return cached_data
4106
+
4107
+ # 获取所有托管规则
4108
+ hosting_list = self.query_hosting_info_list()
4109
+
4110
+ if not hosting_list:
4111
+ log('未找到任何托管规则')
4112
+ return None
4113
+
4114
+ # 遍历所有托管规则,查找匹配的SKC和活动
4115
+ for hosting in hosting_list:
4116
+ hosting_id = hosting.get('hosting_id')
4117
+ if not hosting_id:
4118
+ continue
4119
+
4120
+ log(f'查询托管规则: hosting_id={hosting_id}, hosting_name={hosting.get("hosting_name")}')
4121
+
4122
+ # 获取该托管规则下的商品
4123
+ goods_list = self.query_hosting_activity_goods(hosting_id)
4124
+
4125
+ # 在商品列表中查找匹配的SKC
4126
+ for goods_item in goods_list:
4127
+ skc_name = goods_item.get('skc_name', '')
4128
+
4129
+ # 匹配SKC名称
4130
+ if skc_name != skc:
4131
+ continue
4132
+
4133
+ # 检查活动信息
4134
+ activity_info = goods_item.get('activity_info', {})
4135
+ goods_activity_id = activity_info.get('activity_id')
4136
+
4137
+ # 匹配活动ID
4138
+ try:
4139
+ if int(goods_activity_id) != target_activity_id:
4140
+ continue
4141
+ except (ValueError, TypeError):
4142
+ continue
4143
+
4144
+ log(f'找到匹配的SKC: {skc_name}, activity_id={goods_activity_id}')
4145
+
4146
+ # 提取活动库存
4147
+ act_stock_num = goods_item.get('act_stock_num', 0)
4148
+
4149
+ # 获取第一个SKU的价格信息
4150
+ sku_info_list = goods_item.get('sku_info_list', [])
4151
+ if not sku_info_list:
4152
+ log(f'SKC {skc_name} 没有SKU信息')
4153
+ continue
4154
+
4155
+ first_sku = sku_info_list[0]
4156
+ sku_price = first_sku.get('sku_price', 0)
4157
+ act_sku_price = first_sku.get('act_sku_price', 0)
4158
+ currency = first_sku.get('currency', 'CNY')
4159
+
4160
+ # 构建返回结果
4161
+ result = {
4162
+ 'skc_name' : skc_name,
4163
+ 'goods_name' : goods_item.get('goods_name', ''),
4164
+ 'image_url' : goods_item.get('image_url', ''),
4165
+ 'activity_id' : goods_activity_id,
4166
+ 'act_stock_num': act_stock_num,
4167
+ 'sku_price' : sku_price,
4168
+ 'act_sku_price': act_sku_price,
4169
+ 'currency' : currency,
4170
+ 'start_time' : activity_info.get('start_time', ''),
4171
+ 'end_time' : activity_info.get('end_time', ''),
4172
+ 'time_zone' : activity_info.get('time_zone', ''),
4173
+ }
4174
+
4175
+ log(f'SKC供货价: {sku_price} {currency}, 活动价: {act_sku_price} {currency}, 活动库存: {act_stock_num}')
4176
+
4177
+ # 保存缓存
4178
+ write_dict_to_file(cache_file, result)
4179
+
4180
+ return result
4181
+
4182
+ log(f'未找到匹配的SKC和活动: skc={skc}, activity_id={activity_id}')
4183
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qrpa
3
- Version: 1.1.35
3
+ Version: 1.1.36
4
4
  Summary: qsir's rpa library
5
5
  Author: QSir
6
6
  Author-email: QSir <1171725650@qq.com>
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes