@@ -0,0 +1,35 @@ |
||
1 |
+from utils import wsgjp |
|
2 |
+from django_response import response |
|
3 |
+ |
|
4 |
+def get_gjp_stock_purchase_list(request): |
|
5 |
+ begin_time = request.POST.get('begin_time') |
|
6 |
+ end_time = request.POST.get('end_time') |
|
7 |
+ token = request.POST.get('token', '') |
|
8 |
+ pageno = request.POST.get('pageno', 1) |
|
9 |
+ pagesize = request.POST.get('pagesize', 1000) |
|
10 |
+ |
|
11 |
+ params = { |
|
12 |
+ 'pageno': pageno, |
|
13 |
+ 'pagesize': pagesize, |
|
14 |
+ 'begintime': begin_time, |
|
15 |
+ 'endtime': end_time |
|
16 |
+ } |
|
17 |
+ |
|
18 |
+ res = wsgjp.wsgjp_post('beefun.gjsstockbilldetail.list', params, token) |
|
19 |
+ |
|
20 |
+ purchase_list = res['response']['billdetails'] |
|
21 |
+ |
|
22 |
+ lens_purchase_list = [] |
|
23 |
+ for item in purchase_list: |
|
24 |
+ if (item['bfullname'] == '深圳今日捷成实业有限公司'): |
|
25 |
+ lens_purchase_list.append({ |
|
26 |
+ '采购订单编号': item['number'], |
|
27 |
+ '商品编码': item['pusercode'], |
|
28 |
+ 'date': item['date'], |
|
29 |
+ '采购数量': item['qty'], |
|
30 |
+ '采购单价': item['price'], |
|
31 |
+ '供应商': item['bfullname'], |
|
32 |
+ '过账日期': item['overtime'] |
|
33 |
+ }) |
|
34 |
+ |
|
35 |
+ return response(200, 'Get Wsgjp Stock List Success', '获取管家婆管金所进货单列表', data=lens_purchase_list) |
@@ -1,9 +1,12 @@ |
||
1 |
-from api import wsgjp_views |
|
1 |
+from api import wsgjp_views, purchase_views |
|
2 | 2 |
from django.conf.urls import url |
3 | 3 |
|
4 | 4 |
urlpatterns = [ |
5 | 5 |
url(r"^auth/callback$", wsgjp_views.auth_callback, |
6 | 6 |
name="wsgjp_auth_callback"), |
7 |
+ url(r"^refrsh/token$", wsgjp_views.refrsh_token, |
|
8 |
+ name="wsgjp_refrsh_token"), |
|
9 |
+ |
|
7 | 10 |
url(r"^stock/list$", wsgjp_views.get_stock_list, |
8 | 11 |
name="wsgjp_get_stock_list"), |
9 | 12 |
url(r"^type/list", wsgjp_views.get_type_list, name="wsgjp_get_type_list"), |
@@ -15,4 +18,12 @@ urlpatterns = [ |
||
15 | 18 |
name="wsgjp_get_goods_with_keyword"), |
16 | 19 |
url(r"^goods/stock/list", wsgjp_views.get_goods_stock_list, |
17 | 20 |
name="wsgjp_get_goods_stock_list"), |
21 |
+ |
|
22 |
+ #单据相关 |
|
23 |
+ url(r"^generate/daily/sale", wsgjp_views.generate_daily_sale, |
|
24 |
+ name="wsgjp_generate_daily_sale"), |
|
25 |
+ |
|
26 |
+ |
|
27 |
+ url(r"^stock/purchase/list", purchase_views.get_gjp_stock_purchase_list, |
|
28 |
+ name="get_gjp_stock_purchase_list"), |
|
18 | 29 |
] |
@@ -10,32 +10,39 @@ import hashlib |
||
10 | 10 |
from Crypto.Cipher import AES |
11 | 11 |
import redis |
12 | 12 |
|
13 |
+# from baseopensdk import BaseClient, JSON |
|
14 |
+# from baseopensdk.api.base.v1 import * |
|
15 |
+# from dotenv import load_dotenv, find_dotenv |
|
13 | 16 |
|
17 |
+from wsgjp.models import WsgjpGoodsStockInfo |
|
18 |
+ |
|
19 |
+# load_dotenv(find_dotenv()) |
|
14 | 20 |
def auth_callback(request): |
15 |
- appkey = request.GET.get("appkey") |
|
16 |
- auth_code = request.GET.get("auth_code") |
|
17 |
- keyword = request.GET.get("keyword") |
|
21 |
+ appkey = request.GET.get('appkey') |
|
22 |
+ auth_code = request.GET.get('auth_code') |
|
23 |
+ keyword = request.GET.get('keyword') |
|
18 | 24 |
|
19 |
- now = datetime.now()+timedelta(hours=8) |
|
20 |
- time_stamp = now.strftime("%Y-%m-%d %H:%M:%S") |
|
25 |
+ now = datetime.now() |
|
26 |
+ time_stamp = now.strftime('%Y-%m-%d %H:%M:%S') |
|
21 | 27 |
appsecret = settings.WSGJP['appsecret'] |
28 |
+ # appkey = settings.WSGJP['appsecret'] |
|
22 | 29 |
iv = appsecret[5: 21] |
23 | 30 |
|
24 | 31 |
bs = AES.block_size |
25 | 32 |
def padding(s): return s + (bs - len(s) % bs) * chr(bs - len(s) % bs) |
26 | 33 |
jsonParam = json.dumps( |
27 |
- {"TimeStamp": time_stamp, "GrantType": "auth_token", "AuthParam": auth_code}) |
|
34 |
+ {'TimeStamp': time_stamp, 'GrantType': 'auth_token', 'AuthParam': auth_code}) |
|
28 | 35 |
jsonParam = padding(jsonParam) |
29 | 36 |
|
30 | 37 |
cipher = AES.new(appsecret.encode('utf8'), AES.MODE_CBC, iv.encode('utf8')) |
31 | 38 |
p = cipher.encrypt(jsonParam.encode('utf8')) |
32 | 39 |
p = base64.b64encode(p) |
33 | 40 |
|
34 |
- sign = json.dumps({"appkey": appkey, "p": p.decode( |
|
35 |
- 'utf8'), "signkey": "kodo"}).replace(' ', '') |
|
41 |
+ sign = json.dumps({'appkey': appkey, 'p': p.decode( |
|
42 |
+ 'utf8'), 'signkey': 'kodo'}).replace(' ', '') |
|
36 | 43 |
sign = hashlib.sha256(sign.encode('utf8')).hexdigest() |
37 | 44 |
|
38 |
- headers = {"ContentType": "application/x-www-form-urlencoded;charset=utf-8"} |
|
45 |
+ headers = {'ContentType': 'application/x-www-form-urlencoded;charset=utf-8'} |
|
39 | 46 |
|
40 | 47 |
url = 'http://apigateway.wsgjp.com.cn/api/token' |
41 | 48 |
res = requests.post(url, data={ |
@@ -60,23 +67,66 @@ def auth_callback(request): |
||
60 | 67 |
else: |
61 | 68 |
return response(200, 'Get Wsgjp Token Fail', '获取管家婆Token失败', data=res) |
62 | 69 |
|
70 |
+def refrsh_token(request): |
|
71 |
+ auth_token = request.POST.get('token', '') |
|
72 |
+ |
|
73 |
+ now = datetime.now() |
|
74 |
+ time_stamp = now.strftime('%Y-%m-%d %H:%M:%S') |
|
75 |
+ appsecret = settings.WSGJP['appsecret'] |
|
76 |
+ appkey = settings.WSGJP['appkey'] |
|
77 |
+ iv = appsecret[5: 21] |
|
78 |
+ |
|
79 |
+ bs = AES.block_size |
|
80 |
+ def padding(s): return s + (bs - len(s) % bs) * chr(bs - len(s) % bs) |
|
81 |
+ jsonParam = json.dumps( |
|
82 |
+ {'TimeStamp': time_stamp, 'GrantType': 'auth_token', 'AuthParam': auth_token}) |
|
83 |
+ jsonParam = padding(jsonParam) |
|
84 |
+ |
|
85 |
+ cipher = AES.new(appsecret.encode('utf8'), AES.MODE_CBC, iv.encode('utf8')) |
|
86 |
+ p = cipher.encrypt(jsonParam.encode('utf8')) |
|
87 |
+ p = base64.b64encode(p) |
|
88 |
+ |
|
89 |
+ sign = json.dumps({'appkey': appkey, 'p': p.decode( |
|
90 |
+ 'utf8'), 'signkey': 'kodo'}).replace(' ', '') |
|
91 |
+ sign = hashlib.sha256(sign.encode('utf8')).hexdigest() |
|
63 | 92 |
|
64 |
-def save_token_in_redis(token): |
|
65 |
- redis_conn = redis.Redis( |
|
66 |
- host='127.0.0.1', port=6379, password='your pw', db=0) |
|
93 |
+ headers = {'ContentType': 'application/x-www-form-urlencoded;charset=utf-8'} |
|
67 | 94 |
|
95 |
+ url = 'http://apigateway.wsgjp.com.cn/api/token' |
|
96 |
+ res = requests.post(url, data={ |
|
97 |
+ 'appkey': appkey, |
|
98 |
+ 'p': p, |
|
99 |
+ 'sign': sign |
|
100 |
+ }).text |
|
101 |
+ |
|
102 |
+ res = json.loads(res) |
|
103 |
+ print(res) |
|
104 |
+ |
|
105 |
+ iserror = res.get('iserror', '') |
|
106 |
+ |
|
107 |
+ if not iserror: |
|
108 |
+ decrypt_cipher = AES.new(appsecret.encode( |
|
109 |
+ 'utf8'), AES.MODE_CBC, iv.encode('utf8')) |
|
110 |
+ decrypt_token = res.get('response', '').get('response', '') |
|
111 |
+ decrypt_token = base64.b64decode(decrypt_token) |
|
112 |
+ token = decrypt_cipher.decrypt(decrypt_token) |
|
113 |
+ token = token.decode('utf8') |
|
114 |
+ return response(200, 'Get Wsgjp Token Success', '获取管家婆Token成功', data=token) |
|
115 |
+ else: |
|
116 |
+ return response(200, 'Get Wsgjp Token Fail', '获取管家婆Token失败', data=res) |
|
68 | 117 |
|
69 | 118 |
def get_stock_list(request): |
70 | 119 |
api_url = 'http://apigateway.wsgjp.com.cn/allnewapi' |
120 |
+ token = request.POST.get('token', '') |
|
71 | 121 |
|
72 |
- now = datetime.now()+timedelta(hours=8) |
|
122 |
+ now = datetime.now() |
|
73 | 123 |
params = { |
74 | 124 |
'appkey': settings.WSGJP['appkey'], |
75 | 125 |
'method': 'erp.stock.list', |
76 | 126 |
'pageno': 1, |
77 | 127 |
'pagesize': 1000, |
78 |
- 'timestamp': now.strftime("%Y-%m-%d %H:%M:%S"), |
|
79 |
- 'token': '5bvSiVFz7jpxelAAc4pBB1vG311T6n5od1IXPGkC' |
|
128 |
+ 'timestamp': now.strftime('%Y-%m-%d %H:%M:%S'), |
|
129 |
+ 'token': token |
|
80 | 130 |
} |
81 | 131 |
|
82 | 132 |
sign = get_wsgjp_sign(params) |
@@ -91,16 +141,17 @@ def get_stock_list(request): |
||
91 | 141 |
def get_goods_list(request): |
92 | 142 |
pagenum = int(request.POST.get('pagenum', 1)) |
93 | 143 |
pagesize = int(request.POST.get('pagesize', 150)) |
144 |
+ token = request.POST.get('token', '') |
|
94 | 145 |
api_url = 'http://apigateway.wsgjp.com.cn/allnewapi' |
95 | 146 |
|
96 |
- now = datetime.now()+timedelta(hours=8) |
|
147 |
+ now = datetime.now() |
|
97 | 148 |
params = { |
98 | 149 |
'appkey': settings.WSGJP['appkey'], |
99 | 150 |
'method': 'erp.ptype.list', |
100 | 151 |
'pageno': pagenum, |
101 | 152 |
'pagesize': pagesize, |
102 |
- 'timestamp': now.strftime("%Y-%m-%d %H:%M:%S"), |
|
103 |
- 'token': '5bvSiVFz7jpxelAAc4pBB1vG311T6n5od1IXPGkC', |
|
153 |
+ 'timestamp': now.strftime('%Y-%m-%d %H:%M:%S'), |
|
154 |
+ 'token': token, |
|
104 | 155 |
'timetype': 0, |
105 | 156 |
'begintime': '2000-01-01 00:00:00', |
106 | 157 |
'endtime': '2025-01-01 00:00:00', |
@@ -117,13 +168,14 @@ def get_goods_list(request): |
||
117 | 168 |
|
118 | 169 |
def get_type_list(request): |
119 | 170 |
api_url = 'http://apigateway.wsgjp.com.cn/allnewapi' |
171 |
+ token = request.POST.get('token', '') |
|
120 | 172 |
|
121 |
- now = datetime.now()+timedelta(hours=8) |
|
173 |
+ now = datetime.now() |
|
122 | 174 |
params = { |
123 | 175 |
'appkey': settings.WSGJP['appkey'], |
124 | 176 |
'method': 'erp.ptype.classlist', |
125 |
- 'timestamp': now.strftime("%Y-%m-%d %H:%M:%S"), |
|
126 |
- 'token': '5bvSiVFz7jpxelAAc4pBB1vG311T6n5od1IXPGkC', |
|
177 |
+ 'timestamp': now.strftime('%Y-%m-%d %H:%M:%S'), |
|
178 |
+ 'token': token, |
|
127 | 179 |
} |
128 | 180 |
|
129 | 181 |
sign = get_wsgjp_sign(params) |
@@ -137,14 +189,15 @@ def get_type_list(request): |
||
137 | 189 |
|
138 | 190 |
def get_goods_by_keyword(request): |
139 | 191 |
keyword = request.POST.get('keyword', '') |
192 |
+ token = request.POST.get('token', '') |
|
140 | 193 |
|
141 | 194 |
api_url = 'http://apigateway.wsgjp.com.cn/allnewapi' |
142 |
- now = datetime.now()+timedelta(hours=8) |
|
195 |
+ now = datetime.now() |
|
143 | 196 |
params = { |
144 | 197 |
'appkey': settings.WSGJP['appkey'], |
145 | 198 |
'method': 'erp.ptype.listbykey', |
146 |
- 'timestamp': now.strftime("%Y-%m-%d %H:%M:%S"), |
|
147 |
- 'token': '5bvSiVFz7jpxelAAc4pBB1vG311T6n5od1IXPGkC', |
|
199 |
+ 'timestamp': now.strftime('%Y-%m-%d %H:%M:%S'), |
|
200 |
+ 'token': token, |
|
148 | 201 |
'keyword': keyword |
149 | 202 |
} |
150 | 203 |
|
@@ -158,18 +211,20 @@ def get_goods_by_keyword(request): |
||
158 | 211 |
|
159 | 212 |
|
160 | 213 |
def get_goods_stock_list(request): |
161 |
- ptypeids = request.POST.get('ptypeids', '[]') |
|
162 | 214 |
ktypeids = request.POST.get('ktypeids', '["89257248480959320"]') # 默认北京主仓库 |
163 | 215 |
pagenum = int(request.POST.get('pagenum', 1)) |
164 | 216 |
pagesize = int(request.POST.get('pagesize', 150)) |
217 |
+ token = request.POST.get('token', '') |
|
165 | 218 |
|
219 |
+ ptypeids = json.dumps(['528088895131030216', '565520855691786916', '2789748684800635087', '528370117226110691', '528088895145627771', '1634850617510978570', '526960317371329313', '2789749264469905534', '2755691821258974547', '96299211990509973', '526961618689488761', '528088944746100823', '2789746398085522693', '528654572538498468', '2771453807600541892', '527522779555210628', '530336103303312452', '528654996976265868', '2782991055968095560', '526961618684102157', '511476313508046333', '100240908638502199', '100240908651352134', '528654997045936440', '1633164740512192893', '2789748089336817715', '2789749410943142300', '2771453807605421616', '528654858697333445', '2782991276095616446', '2782990858372964442']) |
|
220 |
+ |
|
166 | 221 |
api_url = 'http://apigateway.wsgjp.com.cn/allnewapi' |
167 |
- now = datetime.now()+timedelta(hours=8) |
|
222 |
+ now = datetime.now() |
|
168 | 223 |
params = { |
169 | 224 |
'appkey': settings.WSGJP['appkey'], |
170 | 225 |
'method': 'erp.goodsstocks.list', |
171 |
- 'timestamp': now.strftime("%Y-%m-%d %H:%M:%S"), |
|
172 |
- 'token': '5bvSiVFz7jpxelAAc4pBB1vG311T6n5od1IXPGkC', |
|
226 |
+ 'timestamp': now.strftime('%Y-%m-%d %H:%M:%S'), |
|
227 |
+ 'token': token, |
|
173 | 228 |
'ptypeids': ptypeids, |
174 | 229 |
'ktypeids': ktypeids, |
175 | 230 |
'pageno': pagenum, |
@@ -182,6 +237,24 @@ def get_goods_stock_list(request): |
||
182 | 237 |
res = requests.post(api_url, data=params).text |
183 | 238 |
|
184 | 239 |
res = json.loads(res) |
240 |
+ |
|
241 |
+ stock_list = [] |
|
242 |
+ for stock in res['response']['goodsstocks']: |
|
243 |
+ stock_list += WsgjpGoodsStockInfo( |
|
244 |
+ ptypeid=stock['ptypeid'], |
|
245 |
+ ktypeid=stock['ktypeid'], |
|
246 |
+ skuid=stock['skuid'], |
|
247 |
+ qty=stock['qty'], |
|
248 |
+ saleqty=stock['saleqty'], |
|
249 |
+ ) |
|
250 |
+ |
|
251 |
+ WsgjpGoodsStockInfo.objects.bulk_create(stock_list) |
|
252 |
+ |
|
253 |
+ baseClient = BaseClient.builder().app_token('MXVgbfaPWaV9jospaK5cwC0bnUb').personal_base_token('pt-ox1qP639VxwzmbhSwRRYph8-vqVf283CYCydb2iYAQAAHECCyALAIO2wzkZg').build() |
|
254 |
+ |
|
255 |
+ stock_request = BatchCreateAppTableRecordRequest.builder().table_id('tbl3xncRKTj3nqOw').request_body(request_body).build() |
|
256 |
+ stock_response = baseClient.batch_create_app_table_record(stock_request) |
|
257 |
+ |
|
185 | 258 |
return response(200, 'Get Wsgjp Type List Success', '获取管家婆商品库存列表成功', data=res) |
186 | 259 |
|
187 | 260 |
|
@@ -196,3 +269,119 @@ def get_wsgjp_sign(params): |
||
196 | 269 |
sign.update(sign_str.encode('utf8')) |
197 | 270 |
|
198 | 271 |
return sign.hexdigest() |
272 |
+ |
|
273 |
+def generate_daily_sale(request): |
|
274 |
+ token = request.POST.get('token', '') |
|
275 |
+ |
|
276 |
+ api_url = 'http://apigateway.wsgjp.com.cn/allnewapi' |
|
277 |
+ now = datetime.now() |
|
278 |
+ params = { |
|
279 |
+ 'appkey': settings.WSGJP['appkey'], |
|
280 |
+ 'method': 'beefun.gjssaleandbackbilldetail.list', |
|
281 |
+ 'timestamp': now.strftime('%Y-%m-%d %H:%M:%S'), |
|
282 |
+ 'token': token, |
|
283 |
+ 'dlytype': 0, |
|
284 |
+ 'pageno': 1, |
|
285 |
+ 'pagesize': 1000, |
|
286 |
+ 'begintime': now.strftime('%Y-%m-%d') + ' 00:00:00', |
|
287 |
+ 'endtime': now.strftime('%Y-%m-%d') + ' 23:59:59', |
|
288 |
+ } |
|
289 |
+ |
|
290 |
+ sign = get_wsgjp_sign(params) |
|
291 |
+ params['sign'] = sign |
|
292 |
+ |
|
293 |
+ res = requests.post(api_url, data=params).text |
|
294 |
+ |
|
295 |
+ res = json.loads(res) |
|
296 |
+ order_list = res['response']['billdetails'] |
|
297 |
+ tarmon_order_list = [] |
|
298 |
+ |
|
299 |
+ model_code_list = ['jt1122', 'A064S', 'A064Z', 'jt10090', 'A063Z', 'jt10076', 'jt10088', 'jt10095', 'A057Z', 'A065S', 'jt10089', 'A058Z', 'JT10094', 'A067S', 'A067Z', 'A074S', 'A068S', 'A069S', 'jt10093', 'jtA071', 'jt1125', 'jt1123', 'jt1124', 'F072S', 'F072Z', 'jt10087', 'B060X', 'B060RF', 'jt0089', 'jt10092', 'jt10078', 'B070X'] |
|
300 |
+ |
|
301 |
+ model_code_dict = { |
|
302 |
+ "jt1122": "A046S", |
|
303 |
+ "A064S": "A064S", |
|
304 |
+ "A064Z": "A064Z", |
|
305 |
+ "jt10090": "A063S", |
|
306 |
+ "A063Z": "A063Z", |
|
307 |
+ "jt10076": "A047S", |
|
308 |
+ "jt10088": "A057S", |
|
309 |
+ "jt10095": "A057X", |
|
310 |
+ "A057Z": "A057Z", |
|
311 |
+ "A065S": "A065S", |
|
312 |
+ "jt10089": "A058S", |
|
313 |
+ "A058Z": "A058Z", |
|
314 |
+ "JT10094": "A062S", |
|
315 |
+ "A067S": "A067S", |
|
316 |
+ "A067Z": "A067Z", |
|
317 |
+ "A074S": "A074S", |
|
318 |
+ "A068S": "A068S", |
|
319 |
+ "A069S": "A069S", |
|
320 |
+ "jt10093": "A047Z", |
|
321 |
+ "jtA071": "A071S", |
|
322 |
+ "jt1125": "F050S", |
|
323 |
+ "jt1123": "F051S", |
|
324 |
+ "jt1124": "F053S", |
|
325 |
+ "F072S": "F072S", |
|
326 |
+ "F072Z": "F072Z", |
|
327 |
+ "jt10087": "B060S", |
|
328 |
+ "B060X": "B060X", |
|
329 |
+ "B060RF": "B060R", |
|
330 |
+ "jt0089": "B061S", |
|
331 |
+ "jt10092": "B061X", |
|
332 |
+ "jt10078": "B070S", |
|
333 |
+ "B070X": "B070X" |
|
334 |
+ } |
|
335 |
+ |
|
336 |
+ |
|
337 |
+ sale_order_dict = {} |
|
338 |
+ for order in order_list: |
|
339 |
+ if order['pusercode'] in model_code_list: |
|
340 |
+ model_name = model_code_dict[order['pusercode']] |
|
341 |
+ sale_num = -1 if order['billtype'] == '销售退货单' else 1 |
|
342 |
+ if model_name in sale_order_dict.keys(): |
|
343 |
+ sale_order_dict[model_name] = sale_order_dict[model_name] + sale_num |
|
344 |
+ else: |
|
345 |
+ sale_order_dict[model_name] = sale_num |
|
346 |
+ |
|
347 |
+ # baseClient = BaseClient.builder().app_token('MXVgbfaPWaV9jospaK5cwC0bnUb').personal_base_token('pt-ox1qP639VxwzmbhSwRRYph8-vqVf283CYCydb2iYAQAAHECCyALAIO2wzkZg').build() |
|
348 |
+ |
|
349 |
+ # model_request = ListAppTableRecordRequest.builder().table_id('tblK8TlETBi98CuI').page_size(50).build() |
|
350 |
+ # model_response = baseClient.base.v1.app_table_record.list(request) |
|
351 |
+ # model_res = JSON.marshal(response.data, indent=4) |
|
352 |
+ |
|
353 |
+ # model_dict = {} |
|
354 |
+ # for item in model_res['items']: |
|
355 |
+ # model_dict[item['fields']['产品型号']] = item['fields']['腾龙D价'] |
|
356 |
+ |
|
357 |
+ |
|
358 |
+ # sale_order_list =[] |
|
359 |
+ # for model_name, sale_num in sale_order_dict.items(): |
|
360 |
+ # sale_order_list.append(AppTableRecord.builder() |
|
361 |
+ # .fields({ |
|
362 |
+ # '自然月': now.month, |
|
363 |
+ # '日': now.day, |
|
364 |
+ # '省': '北京', |
|
365 |
+ # '销售单位': '腾龙旗舰店', |
|
366 |
+ # '型号': model_name[:-1], |
|
367 |
+ # '卡口': model_name[-1:], |
|
368 |
+ # '支数': sale_num, |
|
369 |
+ # '单价': model_dict[model_name], |
|
370 |
+ # }).build()) |
|
371 |
+ |
|
372 |
+ # batch_sale_request = BatchCreateAppTableRecordRequest.builder().app_token("MXVgbfaPWaV9jospaK5cwC0bnUb").personal_base_token('pt-ox1qP639VxwzmbhSwRRYph8-vqVf283CYCydb2iYAQAAHECCyALAIO2wzkZg').table_id("tblsRc9GRRXKqhvW").request_body(BatchCreateAppTableRecordRequestBody.builder().records(sale_order_list)).build() |
|
373 |
+ |
|
374 |
+ # batch_sale_response = baseClient.bitable.v1.app_table_record.batch_create(batch_sale_request) |
|
375 |
+ |
|
376 |
+ # sale_request = ListAppTableRecordRequest.builder().table_id('tbl3xncRKTj3nqOw').page_size(3000).build() |
|
377 |
+ # sale_response = baseClient.base.v1.app_table_record.list(sale_request) |
|
378 |
+ # sale_res = JSON.marshal(response.data, indent=4) |
|
379 |
+ |
|
380 |
+ # return response(200, 'Get Wsgjp Type List Success', '生成日销售明细成功', data={ |
|
381 |
+ # 'batch_sale_response': batch_sale_response, |
|
382 |
+ # 'sale_response': sale_res, |
|
383 |
+ # }) |
|
384 |
+ |
|
385 |
+ return response(200, 'Get Wsgjp Type List Success', '生成日销售明细成功', data={ |
|
386 |
+ 'sale_order_dict': sale_order_dict, |
|
387 |
+ }) |
@@ -30,7 +30,8 @@ INSTALLED_APPS = [ |
||
30 | 30 |
'django.contrib.sessions', |
31 | 31 |
'django.contrib.messages', |
32 | 32 |
'django.contrib.staticfiles', |
33 |
- 'kodo_work' |
|
33 |
+ 'kodo_work', |
|
34 |
+ 'wsgjp', |
|
34 | 35 |
] |
35 | 36 |
|
36 | 37 |
MIDDLEWARE = [ |
@@ -12,4 +12,5 @@ django-shortuuidfield==0.1.3 |
||
12 | 12 |
|
13 | 13 |
redis==4.3.4 |
14 | 14 |
redis-extensions==4.1.1 |
15 |
-pyqywe-token==1.0.0 |
|
15 |
+pyqywe-token==1.0.0 |
|
16 |
+mysqlclient==2.2.0 |
@@ -0,0 +1,66 @@ |
||
1 |
+import pandas as pd |
|
2 |
+import smtplib |
|
3 |
+from email.mime.text import MIMEText |
|
4 |
+from email.mime.multipart import MIMEMultipart |
|
5 |
+from email.mime.application import MIMEApplication |
|
6 |
+from email.header import Header |
|
7 |
+import datetime |
|
8 |
+ |
|
9 |
+from api.wsgjp_views import generate_daily_sale |
|
10 |
+ |
|
11 |
+ |
|
12 |
+def create_excel_file(file_path, data): |
|
13 |
+ """创建Excel文件""" |
|
14 |
+ df = pd.DataFrame(data) |
|
15 |
+ df.to_excel(file_path, index=False) |
|
16 |
+ print(f"Excel文件已创建: {file_path}") |
|
17 |
+ return file_path |
|
18 |
+ |
|
19 |
+ |
|
20 |
+def send_email_with_excel(sender, receiver, subject, content, excel_file_path, smtp_server, smtp_port, username, password): |
|
21 |
+ """发送带Excel附件的邮件""" |
|
22 |
+ # 创建一个带附件的邮件实例 |
|
23 |
+ message = MIMEMultipart() |
|
24 |
+ message['From'] = Header(sender) |
|
25 |
+ message['To'] = Header(receiver) |
|
26 |
+ message['Subject'] = Header(subject) |
|
27 |
+ |
|
28 |
+ # 邮件正文内容 |
|
29 |
+ message.attach(MIMEText(content, 'plain', 'utf-8')) |
|
30 |
+ |
|
31 |
+ # 添加Excel附件 |
|
32 |
+ with open(excel_file_path, 'rb') as file: |
|
33 |
+ attach = MIMEApplication(file.read(), Name=excel_file_path.split('/')[-1]) |
|
34 |
+ attach['Content-Disposition'] = f'attachment; filename="{excel_file_path.split("/")[-1]}"' # 确保文件名正确 |
|
35 |
+ message.attach(attach) |
|
36 |
+ |
|
37 |
+ # 发送邮件 |
|
38 |
+ try: |
|
39 |
+ smtp = smtplib.SMTP_SSL(smtp_server, smtp_port) |
|
40 |
+ smtp.login(username, password) |
|
41 |
+ smtp.sendmail(sender, receiver, message.as_string()) |
|
42 |
+ smtp.quit() |
|
43 |
+ print("邮件发送成功") |
|
44 |
+ except Exception as e: |
|
45 |
+ print(f"邮件发送失败: {e}") |
|
46 |
+ |
|
47 |
+ |
|
48 |
+if __name__ == "__main__": |
|
49 |
+ # 配置参数 |
|
50 |
+ excel_file = "example.xlsx" |
|
51 |
+ sender = "zhengjf@kodo.com.cn" |
|
52 |
+ receiver = "wx.qyroot@kodo.com.cn" |
|
53 |
+ subject = "测试邮件带Excel附件" |
|
54 |
+ content = "这是一封测试邮件,包含Excel附件。" |
|
55 |
+ smtp_server = "smtp.exmail.qq.com" # 例如:smtp.qq.com 或 smtp.gmail.com |
|
56 |
+ smtp_port = 465 # 通常SSL端口为465 |
|
57 |
+ username = "zhengjf@kodo.com.cn" |
|
58 |
+ password = "3KaF3iBqt7PtR4u4" # 注意:对于某些邮箱,需要使用应用专用密码 |
|
59 |
+ |
|
60 |
+ # 创建Excel文件 |
|
61 |
+ now = datetime.datetime.now() |
|
62 |
+ excel_list = generate_daily_sale("lVtlSo9999ekrxNQzjWEK7OIxybRb8SgzQuIOAJw") |
|
63 |
+ create_excel_file(f"日销售明细(北京盈多){now.strftime('%Y.%m.%d')}.xlsx", excel_list) |
|
64 |
+ |
|
65 |
+ # 发送邮件 |
|
66 |
+ send_email_with_excel(sender, receiver, subject, content, excel_file, smtp_server, smtp_port, username, password) |
@@ -0,0 +1,36 @@ |
||
1 |
+from django.conf import settings |
|
2 |
+ |
|
3 |
+import base64 |
|
4 |
+import requests |
|
5 |
+from datetime import datetime, timedelta |
|
6 |
+import json |
|
7 |
+import hashlib |
|
8 |
+from Crypto.Cipher import AES |
|
9 |
+ |
|
10 |
+def wsgjp_post(method, params, token): |
|
11 |
+ api_url = 'http://apigateway.wsgjp.com.cn/allnewapi' |
|
12 |
+ |
|
13 |
+ now = datetime.now() |
|
14 |
+ params['timestamp'] = now.strftime('%Y-%m-%d %H:%M:%S') |
|
15 |
+ params['method'] = method |
|
16 |
+ params['appkey'] = settings.WSGJP['appkey'] |
|
17 |
+ params['token'] = token |
|
18 |
+ |
|
19 |
+ sign = get_wsgjp_sign(params) |
|
20 |
+ params['sign'] = sign |
|
21 |
+ |
|
22 |
+ res = requests.post(api_url, data=params).text |
|
23 |
+ res = json.loads(res) |
|
24 |
+ |
|
25 |
+ return res |
|
26 |
+def get_wsgjp_sign(params): |
|
27 |
+ sign_str = '' |
|
28 |
+ |
|
29 |
+ for (key, value) in sorted(params.items()): |
|
30 |
+ sign_str += key + str(value) |
|
31 |
+ |
|
32 |
+ sign_str += 'kodo' |
|
33 |
+ sign = hashlib.md5() |
|
34 |
+ sign.update(sign_str.encode('utf8')) |
|
35 |
+ |
|
36 |
+ return sign.hexdigest() |
@@ -0,0 +1,3 @@ |
||
1 |
+from django.contrib import admin |
|
2 |
+ |
|
3 |
+# Register your models here. |
@@ -0,0 +1,6 @@ |
||
1 |
+from django.apps import AppConfig |
|
2 |
+ |
|
3 |
+ |
|
4 |
+class WsgjpConfig(AppConfig): |
|
5 |
+ default_auto_field = 'django.db.models.BigAutoField' |
|
6 |
+ name = 'wsgjp' |
@@ -0,0 +1,32 @@ |
||
1 |
+# Generated by Django 3.2.8 on 2025-07-29 09:20 |
|
2 |
+ |
|
3 |
+from django.db import migrations, models |
|
4 |
+ |
|
5 |
+ |
|
6 |
+class Migration(migrations.Migration): |
|
7 |
+ |
|
8 |
+ initial = True |
|
9 |
+ |
|
10 |
+ dependencies = [ |
|
11 |
+ ] |
|
12 |
+ |
|
13 |
+ operations = [ |
|
14 |
+ migrations.CreateModel( |
|
15 |
+ name='WsgjpGoodsStockInfo', |
|
16 |
+ fields=[ |
|
17 |
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
|
18 |
+ ('status', models.BooleanField(default=True, help_text='Status', verbose_name='status')), |
|
19 |
+ ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')), |
|
20 |
+ ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')), |
|
21 |
+ ('ptypeid', models.CharField(blank=True, help_text='商品id', max_length=255, null=True, verbose_name='ptypeid')), |
|
22 |
+ ('ktypeid', models.CharField(blank=True, help_text='仓库id', max_length=255, null=True, verbose_name='ktypeid')), |
|
23 |
+ ('skuid', models.CharField(blank=True, help_text='skuid', max_length=255, null=True, verbose_name='skuid')), |
|
24 |
+ ('qty', models.IntegerField(default=0, help_text='数量', verbose_name='qty')), |
|
25 |
+ ('saleqty', models.IntegerField(default=0, help_text='可销售库存数量', verbose_name='value')), |
|
26 |
+ ], |
|
27 |
+ options={ |
|
28 |
+ 'verbose_name': '管家婆erp商品库存信息', |
|
29 |
+ 'verbose_name_plural': '会员商品信息', |
|
30 |
+ }, |
|
31 |
+ ), |
|
32 |
+ ] |
@@ -0,0 +1,28 @@ |
||
1 |
+from django.db import models |
|
2 |
+from django.utils.translation import ugettext_lazy as _ |
|
3 |
+from django_models_ext import BaseModelMixin, upload_file_path, upload_file_url, upload_path |
|
4 |
+ |
|
5 |
+# Create your models here. |
|
6 |
+class WsgjpGoodsStockInfo(BaseModelMixin): |
|
7 |
+ ptypeid = models.CharField(_(u'ptypeid'), max_length=255, blank=True, null=True, help_text=u'商品id') |
|
8 |
+ ktypeid = models.CharField(_(u'ktypeid'), max_length=255, blank=True, null=True, help_text=u'仓库id') |
|
9 |
+ skuid = models.CharField(_(u'skuid'), max_length=255, blank=True, null=True, help_text=u'skuid') |
|
10 |
+ |
|
11 |
+ qty = models.IntegerField(_(u'qty'), default=0, help_text=u'数量') |
|
12 |
+ saleqty = models.IntegerField(_(u'value'), default=0, help_text=u'可销售库存数量') |
|
13 |
+ |
|
14 |
+ class Meta: |
|
15 |
+ verbose_name = _(u'管家婆erp商品库存信息') |
|
16 |
+ verbose_name_plural = _(u'会员商品信息') |
|
17 |
+ |
|
18 |
+ def __unicode__(self): |
|
19 |
+ return '%d' % self.pk |
|
20 |
+ |
|
21 |
+ def data(self, user_id=None): |
|
22 |
+ return { |
|
23 |
+ 'ptypeid': self.ptypeid, |
|
24 |
+ 'ktypeid': self.ktypeid, |
|
25 |
+ 'skuid': self.skuid, |
|
26 |
+ 'qty': self.qty, |
|
27 |
+ 'saleqty': self.saleqty, |
|
28 |
+ } |
@@ -0,0 +1,3 @@ |
||
1 |
+from django.test import TestCase |
|
2 |
+ |
|
3 |
+# Create your tests here. |
@@ -0,0 +1,3 @@ |
||
1 |
+from django.shortcuts import render |
|
2 |
+ |
|
3 |
+# Create your views here. |