Merge branch 'master' of git.xfoto.com.cn:kodo_work/server

huangqimin001 21 分钟之前
父节点
当前提交
8553abc8c6
共有 15 个文件被更改,包括 445 次插入31 次删除
  1. 35 0
      api/purchase_views.py
  2. 12 1
      api/wsgjp_urls.py
  3. 217 28
      api/wsgjp_views.py
  4. 2 1
      kodo_work/settings.py
  5. 2 1
      requirements.txt
  6. 66 0
      utils/send_excel_email.py
  7. 36 0
      utils/wsgjp.py
  8. 0 0
      wsgjp/__init__.py
  9. 3 0
      wsgjp/admin.py
  10. 6 0
      wsgjp/apps.py
  11. 32 0
      wsgjp/migrations/0001_initial.py
  12. 0 0
      wsgjp/migrations/__init__.py
  13. 28 0
      wsgjp/models.py
  14. 3 0
      wsgjp/tests.py
  15. 3 0
      wsgjp/views.py

+ 35 - 0
api/purchase_views.py

@@ -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)

+ 12 - 1
api/wsgjp_urls.py

@@ -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
 ]

+ 217 - 28
api/wsgjp_views.py

@@ -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
+    })

+ 2 - 1
kodo_work/settings.py

@@ -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 = [

+ 2 - 1
requirements.txt

@@ -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

+ 66 - 0
utils/send_excel_email.py

@@ -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)

+ 36 - 0
utils/wsgjp.py

@@ -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
wsgjp/__init__.py


+ 3 - 0
wsgjp/admin.py

@@ -0,0 +1,3 @@
1
+from django.contrib import admin
2
+
3
+# Register your models here.

+ 6 - 0
wsgjp/apps.py

@@ -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'

+ 32 - 0
wsgjp/migrations/0001_initial.py

@@ -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
wsgjp/migrations/__init__.py


+ 28 - 0
wsgjp/models.py

@@ -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
+        }

+ 3 - 0
wsgjp/tests.py

@@ -0,0 +1,3 @@
1
+from django.test import TestCase
2
+
3
+# Create your tests here.

+ 3 - 0
wsgjp/views.py

@@ -0,0 +1,3 @@
1
+from django.shortcuts import render
2
+
3
+# Create your views here.

pai2 - Gogs: Go Git Service

拍爱

models.py 58B

    from django.db import models # Create your models here.