first commit

This commit is contained in:
yumoqing 2025-07-16 14:27:17 +08:00
commit a9d4966202
3177 changed files with 546555 additions and 0 deletions

View File

@ -0,0 +1,81 @@
# !/d/ymq/py3/bin/python
import asyncio
import getpass
import os
import re
import subprocess
from appPublic.sshx import SSHNode
home = os.getenv('HOME')
kgadget_build = False
class KbossAppDeploy:
def __init__(self, node):
self.node = node
async def update_code(self):
await self.node._l2r("/root/backup/www/www_backup", '~/')
await self.node._run(f'cd ~')
await self.node._run(f'tar xf ./www_backup/kboss.prod.tar.back')
await self.node._run('chmod +x bin/web')
await self.node._run('tar xzf ./www_backup/files.tar.gz')
await self.node._run(f'cp -r ./files/ ~/www/ ')
try:
await self.node._run(f'tar zxf ./www_backup/kboss_nginx.tar.gz')
await self.node._run('sudo cp ./kboss_nginx/*kaiyuancloud.* /etc/nginx/')
await self.node._run(f'sudo cp ./kboss_nginx/kbossprod /etc/nginx/sites-enabled/')
except Exception as e:
print(f"set nginx config fail :{e}")
await self.node._run(f'cd ~')
await self.node._run('bin/web')
print("deploy ok")
async def init_data(self):
await self.node._run(f'mysql -h db -ukboss -pkboss123 kboss_prod < ~/initdata/mysql.ddl.sql')
await self.node._run(f'mysql -h db -ukboss -pkboss123 kboss_prod < ~/initdata/kboss_init.sql')
async def get_remote_data(self):
subprocess.run("tar zcf /root/backup/www/www_backup/files.tar.gz files/", shell=True, capture_output=True, text=True)
async def deploy(self):
await self.get_remote_data()
await self.node.connect()
await self.update_code()
self.node.close()
def default_node(host, user, port):
node = SSHNode(host,
username=user,
port=port,
password=getpass.getpass(f'{user}@{host} password:')
)
return node
if __name__ == '__main__':
import sys
exp = f"python3 {sys.argv[0]} tt@192.168.0.11:10022"
if len(sys.argv) != 2:
print(f'Usage:\n{exp}')
sys.exit(1)
if re.findall(r'^[\w\d]+@\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+$', sys.argv[1]):
user_ip_prod = sys.argv[1]
user, host = user_ip_prod.split('@')
host, port = host.split(':')
if not port:
port = 22
port = int(port)
else:
print(f'ip not defined ip:{sys.argv[1]}')
sys.exit(1)
node = default_node(host, user, port)
if not node:
sys.exit(1)
d = KbossAppDeploy(node)
loop = asyncio.get_event_loop()
loop.run_until_complete(d.deploy())

55
DevOps/kboss_domain.py Normal file
View File

@ -0,0 +1,55 @@
import asyncio
from pyppeteer import launch
async def main(mode):
browser = await launch(headless=False, args=['--disable-blink-features=AutomationControlled'])
page = await browser.newPage()
await page.setViewport({'width': 1020, 'height': 1080})
await page.waitFor(1000)
url = "https://signin.aliyun.com/login.htm#/main"
await page.goto(url)
await page.waitFor(2000)
await page.type('#loginName', 'www_domain@1953083695298848.onaliyun.com')
await page.keyboard.press('Enter')
await page.waitFor(3000)
await page.screenshot({'path': 'screenshot.png'})
await page.type('#loginPassword', 'Kyy@123456789')
await page.keyboard.press('Enter')
await page.waitFor(3000)
await page.screenshot({'path': 'screenshot1.png'})
url = "https://dns.console.aliyun.com/#/dns/setting/kaiyuancloud.cn"
await page.goto(url)
await page.waitFor(3000)
await page.waitForSelector('#keyword')
await page.type('#keyword', mode)
await page.keyboard.press('Enter')
await page.waitFor(1000)
element = await page.querySelector(
'#app-common-page > div > div._1_aZzbvH > div > div.ant-tabs-content.ant-tabs-content-no-animated.ant-tabs-top-content.ant-tabs-card-content > div.ant-tabs-tabpane.ant-tabs-tabpane-active > div:nth-child(2) > div > div > div:nth-child(2) > div.ant-table-wrapper._3PHtW8UK > div > div > div > div > div.ant-table-fixed-right > div > div > table > tbody > tr:nth-child(1) > td > span > span:nth-child(3)'
)
if element:
await element.click()
else:
await page.waitFor(1000)
element = await page.querySelector(
'#app-common-page > div > div._1_aZzbvH > div > div.ant-tabs-content.ant-tabs-content-no-animated.ant-tabs-top-content.ant-tabs-card-content > div.ant-tabs-tabpane.ant-tabs-tabpane-active > div:nth-child(2) > div > div > div:nth-child(2) > div.ant-table-wrapper._3PHtW8UK > div > div > div > div > div.ant-table-fixed-right > div > div > table > tbody > tr:nth-child(4) > td > span > span:nth-child(3)'
)
if element:
await element.click()
await page.screenshot({'path': 'screenshot.png'})
await page.waitFor(2000)
url = "https://account.aliyun.com/logout/logout.htm?spm=a2c1d.8251892.top-nav.dsign-out.2b3c5b76Cv4sYC&oauth_callback=https%3A%2F%2Fdns.console.aliyun.com%2F%3Fspm%3D5176.100251.111252.28.d2344f156kVH5u%26accounttraceid%3D61009978d16c4f1091b041d678f33d56mntp%23%2Fdns%2Fsetting%2Fkaiyuancloud.cn"
await page.goto(url)
await page.waitFor(1000)
await browser.close()
mode = '@'
asyncio.get_event_loop().run_until_complete(main(mode=mode))

Binary file not shown.

7
DevOps/m.files.sh Normal file
View File

@ -0,0 +1,7 @@
#!/bin/bash
SOURCE_DIR="/home/kbossprod/www/files/"
DEST_DIR="root@192.168.0.2:/root/backup/www/files/"
inotifywait -m -r -e create --format "%w%f" "$SOURCE_DIR" | while read NEW_FILE
do
rsync -avz --relative -e "ssh -p 10022" "$NEW_FILE" "$DEST_DIR"
done

11
DevOps/m.sh Normal file
View File

@ -0,0 +1,11 @@
#!/bin/bash
source_dir="/home/kbossprod/kboss.prod.tar.back"
previous_state=$(ls -l $source_dir)
while true; do
sleep 30
current_state=$(ls -l $source_dir)
if [ "$previous_state" != "$current_state" ]; then
scp -P 10022 $source_dir root@192.168.0.2:/root/backup/www
previous_state=$current_state
fi
done

11
README.md Normal file
View File

@ -0,0 +1,11 @@
# Kboss
kaiyuan business operator support system
## Dependent
* [bricks](https://github.com/yumoqing/bricks) use as kboss frontend development framework
* [ahserver](https://github.com/yumoqing/ahserver) as kboss backend application server
* [sqlor](https://github.com/yumoqing/sqlor) used by ahserver for databases operation
* [aiohttp](https://github.com/aio-libs/aiohttp) use as web server.
##

1
alipay/dev/appid.txt Normal file
View File

@ -0,0 +1 @@
2021004106675236

1
alipay/dev/huidiao.txt Normal file
View File

@ -0,0 +1 @@
https://www.kaiyuancloud.cn/dev/pay/payhuidiao.dspy

3
alipay/dev/private.txt Normal file
View File

@ -0,0 +1,3 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCLODFiJDK+3UB2/zELdFuCYzx3diDMLr8pj/yWz01kYxjw96k8yAIRXFBJDxc/PIEQBifASS4irV1TVtbns+L7ANtDnYtFe8ewO+875rJagqq1tIS6IthiWlGg6rmbzrTtYLSNoCy2rt2hoZyhvE9vm96cjTBc+o+WzIsw1Vex/vahSk0JnviX1kiw9vddAUtupuyLcHIV0VOH04MRfT+C8KsDUZNEmCwlGI/DFmO6DFpniy+jlNb3U8yJqD3FTJhky4I90uYvYRvFeGQA7beZwFnL+oOuspk+gBFZBXyPonHMgxR9Olk6gUkXT3nFibnKqtltZIS82oes24dRLZJfAgMBAAECggEAYui0ZRZ0mxeT8jcRwCKV1Qft8K2TVZ0soTmz6e0z/ctN7/z0VsN+fJkKTS2UhY/V3e2RllInnelvcYMzwYATFeMg5GPsi5wKXhHmwLcBJb7Jy7iJx7hz5URn1ByPa7uq3S8kd65BtjR8L5YjMuEXyqKBwNWqc5RsKWX+yd34pPMEQ0qBeOxtAk3ugVhY7WgJu1GcUhseJu/oUC45ARge2AkMz7m7Fi+xxyfDYklcn10s8d8ripRXFBc2Tmg0oHBldjrnNK+o2wqOV/KadmegE5fLntDx4bIe8bXPEZMXWWhWrXG2WpbEBMkBe1GsqIo5XWbEmzbi/xJM68KxeHyk+QKBgQC9EFK+eTQlt5VQ89WSe1s5W2jOs916ILCSKR6a1QesjAk6sUJxh/g9vwm/WhQC8fOXo9oHycqBg860TlbDNS/nX+PoUMWp3LzwTfaboaDOOCQ3DPCrxztHLSObLyYnAHYEU5daLzM2AsBClmqSWv+6OOvQJJ5dCx1be7jcRaqXOwKBgQC8gkQlyexShdkJeAZbrGH4NyCVGUv2wM01mcPW08YHb8xbCzv50Kqvk9Ulej3vRgccKKd3M51RE+1e4p0UDTeYM9crnPMfM2BgFNv0sWM1pSZp0rlpkxG7pPz8t8/muuQjJjy+is82YDhpO3OU2VxWKt6OpG/Mu59+Wy0vUwUnLQKBgQC6lHVUDADuh/IPZdMLMDmirRcNhmu3rrMSSwos+rcMDVa+WVic+fZ92R4hfR/qmCQxLj5pGTeEATPotLbjBoYz7GnaRnwLWhALhqUsiaFMYhM7UMXigEd7wow1BZ69NrNBKc1f7ty3HJfoHtElhjCA8tOlIb43TFS4h6yzlPz5KQKBgFe7dMX1jRP3EUSz5Jmjx9DCr1pU9KK5pofssVV5KC/r2zsAJoCkmduvPML9eneyqrpzPUVf8zZ5xL6lTx+26wneDqVQnWIHAjKVYq0mJZsg6pjTptE4zkb7iXaAgbTLhEPLlvfDGJ8g9wAa2DcNVkkQGJZgd1vccmVXP9dHlx1dAoGBAIayI4cBHVqO9frmRfH64T1Ztxi4OvmJvXlZdocjdwdBNtQEDQ6r6pQR4cDhSBHj9BPo51Qc3rCu4dcxkl78YcbNjUzBzts8KpGwtOavzON36mUG7NUhHDcXqnM7fQWuWsM3WZhZH2y1UeUVsXOIKenqDluVkh9BVEwgZjMEYpE7
-----END RSA PRIVATE KEY-----

3
alipay/dev/public.txt Normal file
View File

@ -0,0 +1,3 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAogRDEu+GlU0KEZfcWS7P2hcsKLB1/shRXw2AF2bozuc1rrfl2noufAEP7ULMd9kw66C8fJd8H/tPIfff2expmQGa5dJBELZqKlMdTtxxa7t5+OGFWZsqzBlCPci9XjVwWfxamLw5IZTX5qocTUkCgFd62y/fpMsQfQPmU1vAdUSWp7CpS0E/ljks1Gl44hv5UOBZdOxEY6/ww+R3mPosycFk3kaMxe4P002kq7gfcNmZdRm8O9i+q0KsG+LF+Q2qDWQ/xO1UF8R4au50DijGk2S2X3bJk1tjytaDTNHZmcJGWP5qNuHZ82KAT42b0iHAg8HO7XqAmCp9bskX+3gSMwIDAQAB
-----END PUBLIC KEY-----

1
alipay/prod/appid.txt Normal file
View File

@ -0,0 +1 @@
2021004120652840

1
alipay/prod/huidiao.txt Normal file
View File

@ -0,0 +1 @@
https://www.kaiyuancloud.cn/pay/payhuidiao.dspy

3
alipay/prod/private.txt Normal file
View File

@ -0,0 +1,3 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCXl2cIrTPP07WqtIdGlskI3G/UCe2APu13MuJQmyk8RK+VlRFv25JTboa24Hdr7gKbatj4+RzTP/EKxOtRVuNeTijLFvRJf3dEgJzWwDa0zU/J40AmGiPGeqJID6mAKFaI2ugRMO/HO7X6fZxGP+fMn0qSErnXtMyveYSRhgrV5HF0Hpbp+6a5vT3ifOXy5fzzlGKLkmlIw6XolRl2xF4/jl7o9BNjQTcBTY50ENyByMXRckX5McTh/fsOsrMmw8CBiJRWf0Vm/01Gt9pqddh1gIlBKb6M8ZSt52lAGMI7phe1ka54hfu4Z2Ofj3WZTUWy1lz8P5zn7oUxrZ8rJAC1AgMBAAECggEAYt6knMwaltoGCqhj8m42AEmFxk4TUSm5x5ywbtJEOsKxomXvUX1sGm5j/rK4MPSzTpqJmRkg68cwd02oDQ0WjlN717nI6obwSwV3Rbln9NRTzeEh3bf+zVz+qvFMJAIrLmdYJJ4+RTt0nUN/wXG8xYC/KjZ8b2vEdE5VYHSEbKvojg1/yX1L4AGmTYXNtRmPyEfWf7tYm5h4aj1j1bkwY/A6VcABTcs1hmD+ab6ejCnEjtBlCLAycEQ6nwktBtwpcZhrzdBOj80ZeoBZEmi0ZajBBwFDjRaKO7QZ2mYcnOczochqdnKuT6OAWtsOyEyCIQsfIXEArIeZiPPk5w3kAQKBgQDTzmC2+IwbhLimJKQvDzmrfs6qXGA+qXfBOTSaEsiInPQdOIqXTOW8uim0+qN7zHoshks8FvnRs4rpikhtPEFRGhy8skynPtJbs0PDm165dtrvlC1JxyRoEk9D+h1NPA33rP9aIWzHomi0TRYWovSKviS2iw/TTShEAvVItnJf1QKBgQC3OKe0NFcHLLIk8lWzU44CAU3M1mbecljzFzfIcIHDWXu/CsMiylcMvSi1PE7Osz6v8/gDQ+HUzT3eFj1zMZsDRwVS4nXQUkTww4wevvsZWct1pX97ut1femaFrwITMInkR6Yj2+IG49GlgoK0RoiUvF1SbEx5jnWIVIn4ewBtYQKBgQCb6UUEKv1nnFEX68z33ytCdDvI5+ro9XJzx5pS+BSpi2+euuo56Z8LR7Y/xGfnT2N3tvtWpksK9DEDLImX70zdWG1i8ZS/X90VJ2ZwbMRTnYwX42la77565U936Hr9SYG2mZ/2Rrh+U6zjXAMwco+0ObdosADcN+W1+r934OVcaQKBgQCoKejKnetum1haTs3XzI2fS4ETy4kZDAyV+S5q2tBO8veADamyadJhz8/oIBUY5C1aI2rz3D8PKN1q1DDMZLAo3uuE+nM1o/zAmkomAhXHW8JBFYgfkRATzO0CL/GQmVFGY3iamvsmZb0K0vGR8tby5LwmpV2/h8BaQ3VqycJHoQKBgGpXBBt1cvKzGe/Ot25jYiZrZ4niPy8R1ENzv8+rTIbO396auCk2h7tsyNOph1ZrNz5W+qr9yLQHqimz2OvkKGxlzSa6o7xDQ0mSeng+hWO0cJcXOhzQh3jjE2fRZUmgTCWISjFLVp78/K9MFSofk5/+hoqYniIEeaSjX+cHn/D1
-----END RSA PRIVATE KEY-----

3
alipay/prod/public.txt Normal file
View File

@ -0,0 +1,3 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgD4YlfnWKd4vEHsim6vxLwustbnBBh9IUJwF5rGJ3b7wjYyzMnQZ36Cgf81A685IQ+Ni9GogNDaUWZx9V+qGxZRwaLbktSLnUNwPMudKlUoPyQtqyygU+Bmwg1B+UBzZsz8eG72qOuvu9xNbT72QZqFxzLlo0vzWldijnaPcqukUhTaeIYe1AObI9v3ySAa72GkGCHaSkQqvBLydCJt2mu3zJYhPMKre1oNmQkGYUxLKCwonbABaugOEl7t1vL8mAMlwFg2ihJbYiogGfr2Imt/Y1jy8rftiW41opX1UQ30rgfRYeuEsKvVwuoyqffGHeBSjs53xZkYStYKj0m+8AQIDAQAB
-----END PUBLIC KEY-----

1
alipay/requirements.txt Normal file
View File

@ -0,0 +1 @@
qrcode

1
alipay/test/appid.txt Normal file
View File

@ -0,0 +1 @@
2021004117685170

1
alipay/test/huidiao.txt Normal file
View File

@ -0,0 +1 @@
https://www.kaiyuancloud.cn/test/pay/payhuidiao.dspy

3
alipay/test/private.txt Normal file
View File

@ -0,0 +1,3 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2eSZvVqn+PKRijVTUt0t6WP5O0JM/F2buhF2sfnQjZf7cnU13GCwIZLOjtko+h484rBitO7d1yCb/90FHnB0nvqsYFSUbLrViU4Zz9iljLqIvo4O+NFli+esbnC6MLs1jkCnfHhNLaXyNBfY+2DX4KYjJ376xBVWtwkb5a+jTWitQzufZwi2ihUgY87jLlxw1eb3R5V0g3cP5fF9zrbNHycPfw+qFu5WcOz22Pq2/WTECY7iX+9boXuzpwXexTm2MK/lhqNJGufWHtdSSKfurso0leMXBwmWkoYQ3s2SyFFFropbDtqio0zbu2QV52Dhmt06tDKYBdTJVcWKRlpqvAgMBAAECggEADyvphy5Uef/+xvbrS7hlvSlzE4iCBafjdgdpZnMpItxTIXKuwy0uVBBTY1Q/vg01Wkfs0VJ6wX8/xt5+/f476lcPELSJXkY27JL3ReL8s/NnpsBYrtLZb8JJywTkVeF6UEHnSVbN0eJWab9KJxWA/z4s0mQZDczcv9K8ZfaT6CadyV5iKmlfChHtU8cVzL/Shnkeg0ynOwNlbRQ7tyT6MCok1Rm/B5BIeRV9wLxdtr4ff14X9rwP+S8UVNNyiEKTX8QB1OT5GsNwmRkWX3Ud/qrb03BKuijbU5ms3K8+XV9SZWR/nZAieJ10zUFx66p1W6hjRQg31VN3v/1LvuwYiQKBgQD6SB4dT3+0tAfUH6O3JwtVgxP3PV7oqH0sWFzy+jXAkg16H6o3rG/FVO09n3sHu4UCx2IO0YzYbRY/x4AgJySUkQx3i1gvEjtMBm+GTuTv3DRKolJIPBFzl+fd6D5KMNm08yQBQgb2O6Nd1pbG8upkEt1BsyJXKe9XyWg6+vyKpQKBgQC6pGzIz7gvksjWyfux+HjUcs1GlYEG+RN5xijsbumIYpA4TxVqz+6l+nH+21Pb/bqckOg7GIIhDE/jHpnibfhAsv062nVgdRF2CRCVjfJWkUwPkiG8yNjDPC0Pe/GN3IcngExcX+ssZrT5DjF2thSKa7rn12iBajsOZIXCzbfTwwKBgD6WrFk+GTySTObiJqnVrMLsraCFi2d5QxxE2LG2mpyWqaIhqwqTJ7xcWZuwdy7e2Qtx2vbDtook9YxrkoH35/DzOP/oK9xRndyMO3WF40CMe9MyNotz4hVbJpPa0UDyaG8U4qsh3OXU0izUTg5gjvcJtKUKbAsKJJ16c4NUYrU1AoGAXvc+qsaWTw5+xlsriBiHUoG/VQTJDAU8FZ/wPq0Igm60NxJ2MUzvfuB5lFWAy9TEWNmacEc+Hxamp0dwwTd3M2RfWMzDIHswkUB3gcEh504yx1FxfR8su9ooi1JjS+1Dj6PGNtJPVN5Fgtvn6yEmPnAmP8To1cB5oA8hyEboHAUCgYEAyTnK5p3pexDtuBD1K5b2dv3oPgZ4QfbPt9vQ2RIYFGJ3GM9T0c5DlVzwZiYHNktNoK4NyogRh2wDK/2M2CZl3XrYUhqQCI4jtr16o77lYl8PA5fsfxNI/pmK/9vJ8UDFxzdvat2nkU18AxMmWQHSM6AMfrrDylDtbUjUdwIJSj8=
-----END RSA PRIVATE KEY-----

3
alipay/test/public.txt Normal file
View File

@ -0,0 +1,3 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgD4YlfnWKd4vEHsim6vxLwustbnBBh9IUJwF5rGJ3b7wjYyzMnQZ36Cgf81A685IQ+Ni9GogNDaUWZx9V+qGxZRwaLbktSLnUNwPMudKlUoPyQtqyygU+Bmwg1B+UBzZsz8eG72qOuvu9xNbT72QZqFxzLlo0vzWldijnaPcqukUhTaeIYe1AObI9v3ySAa72GkGCHaSkQqvBLydCJt2mu3zJYhPMKre1oNmQkGYUxLKCwonbABaugOEl7t1vL8mAMlwFg2ihJbYiogGfr2Imt/Y1jy8rftiW41opX1UQ30rgfRYeuEsKvVwuoyqffGHeBSjs53xZkYStYKj0m+8AQIDAQAB
-----END PUBLIC KEY-----

56
b/Endofday/index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<style type="text/css">
body{
font-family: 'Courgette', cursive;
}
body{
background:#f3f3e1;
}
.wrap{
margin:0 auto;
width:1000px;
}
.logo{
margin-top:50px;
}
.logo h1{
font-size:200px;
color:#8F8E8C;
text-align:center;
margin-bottom:1px;
text-shadow:1px 1px 6px #fff;
}
.logo p{
color:rgb(228, 146, 162);
font-size:20px;
margin-top:1px;
text-align:center;
}
.logo p span{
color:lightgreen;
}
.sub a{
color:white;
background:#8F8E8C;
text-decoration:none;
padding:7px 120px;
font-size:13px;
font-family: arial, serif;
font-weight:bold;
-webkit-border-radius:3em;
-moz-border-radius:.1em;
-border-radius:.1em;
}
</style>
<body>
<div class="wrap">
<div class="logo">
<h1>404</h1>
<p>The Page not Found</p>
<div class="sub">
<p><a href="/">Back</a></p>
</div>
</div>
</div>
</body>

View File

@ -0,0 +1,32 @@
async def supplier_accounts(ns):
"""供应商日结"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
account_config = await sor.R('account_config',{'partytype':'供应商','del_flg':'0'})
provider = await sor.R('provider',{"del_flg":'0','settle_mode':'1'})
for i in provider:
org = await sor.R('organization', {"id": i['orgid'],'del_flg':'0'})
for j in account_config:
acc = await getAccountByName(sor, org[0]['parentid'], i['orgid'], j['subjectname'])
if acc != None:
accountid = await sor.R('acc_balance',{'accountid':acc})
if len(accountid) >= 1:
settle_log = {
'accounting_orgid': org[0]['parentid'],
'providerid': i['orgid'],
'settle_date': await get_business_date(sor=None),
'settle_mode': '1',
'sale_mode': '',
'settle_amt': accountid[0]['balance'],
'business_op': 'SETTLE'
}
ai = SettleAccounting(settle_log)
await ai.accounting(sor)
return {'status': True, 'msg': '成功'}
except Exception as e:
raise e
return {'status': False, 'msg': '失败'}
ret = await supplier_accounts(params_kw)
return ret

View File

@ -0,0 +1,25 @@
async def addOrganization(ns):
"""
添加机构
:param orgname:
:param contactor:
:param contact_method:
:param reseller_id:
:param province_id:
:param city_id:
:param distinct_id:
:param address:
:param main_business:
:param orgcode:
:param license_img:
:param `org_type` VARCHAR(1) comment '机构类型1为机构2为个人客户、3为公司客户':
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
ns['id'] = uuid()
await sor.C('organization', ns)
return {'status': True, 'msg': '添加成功'}
ret = await addOrganization(params_kw)
return ret

View File

@ -0,0 +1,38 @@
async def delOrganization(ns,sor=None):
"""删除机构"""
if not sor:
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
ns['del_flg'] = '1'
await sor.U('organization', ns)
sql_user = """update users set del_flg = 1 where orgid = '%s'""" % ns.get('id')
await sor.sqlExe(sql_user,{})
sql_customer = """update customer set del_flg = 1 where customerid = '%s'""" % ns.get('id')
await sor.sqlExe(sql_customer,{})
dictns = {'parentid': ns['id']}
reacs = await sor.R('organization', dictns)
for i in reacs:
await delOrganization({'id': i['id']},sor)
return {'status': True, 'msg': '删除成功'}
else:
if ns:
ns['del_flg'] = '1'
await sor.U('organization', ns)
sql_user = """update users set del_flg = 1 where orgid = '%s'""" % ns.get('id')
await sor.sqlExe(sql_user, {})
sql_customer = """update customer set del_flg = 1 where customerid = '%s'""" % ns.get('id')
await sor.sqlExe(sql_customer, {})
dictns = {'parentid': ns['id']}
reacs = await sor.R('organization', dictns)
for i in reacs:
await delOrganization({'id': i['id']}, sor)
return {'status': True, 'msg': '删除成功'}
return {'status': False, 'msg': '删除失败'}
ret = await delOrganization(params_kw)
return ret

View File

@ -0,0 +1,55 @@
async def getOrganization(ns):
"""展示机构"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if not ns.get('parentid') and not ns.get('type'):
sql = """select * from organization where org_type = ${org_type}$ and del_flg = 0"""
reacs = await sor.sqlExe(sql,ns)
list = []
dict = {}
if reacs:
for i in reacs:
dict[i['id']] = i
for j in reacs:
if j['parentid'] == None or j['parentid'] == '':
list.append(j)
else:
if 'son' not in dict[j['parentid']]:
dict[j['parentid']]['son'] = []
dict[j['parentid']]['son'].append(j)
return {'status': True, 'data': list}
elif ns.get('parentid'):
sql = """select * from organization where org_type = ${org_type}$ and del_flg = 0 and parentid = ${parentid}$ """
reacs = await sor.sqlExe(sql, ns)
return {'status': True, 'data': reacs}
elif ns.get('type'):
user = await sor.R('users', {'del_flg': '0', 'id': ns['id']})
orgid = user[0]['orgid']
if ns.get('orgname'):
datalist = []
reacs = await sor.R('customer', {'del_flg': '0'})
for i in reacs:
userid = await sor.R('users', {'del_flg': '0', 'id': i['salemanid']})
if len(userid) >= 1:
if userid[0]['orgid'] == orgid:
nss = {'id': i['customerid'], 'pattern': '%' + ns.get('orgname') + '%'}
sql = """select * from organization where del_flg = 0 and orgname like ${pattern}$ and id = ${id}$"""
reacse = await sor.sqlExe(sql, nss)
if len(reacse) >= 1:
datalist.append(reacse[0])
return {'status': True, 'data': datalist}
else:
datalist = []
reacs = await sor.R('customer', {'del_flg': '0'})
for i in reacs:
userid = await sor.R('users', {'del_flg': '0','id':i['salemanid']})
if len(userid) >= 1:
if userid[0]['orgid'] == orgid:
organization = await sor.R('organization', {'del_flg': '0','id':i['customerid']})
if len(organization) >= 1:
if organization[0] not in datalist:
datalist.append(organization[0])
return {'status': True, 'data': datalist}
ret = await getOrganization(params_kw)
return ret

56
b/Organization/index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<style type="text/css">
body{
font-family: 'Courgette', cursive;
}
body{
background:#f3f3e1;
}
.wrap{
margin:0 auto;
width:1000px;
}
.logo{
margin-top:50px;
}
.logo h1{
font-size:200px;
color:#8F8E8C;
text-align:center;
margin-bottom:1px;
text-shadow:1px 1px 6px #fff;
}
.logo p{
color:rgb(228, 146, 162);
font-size:20px;
margin-top:1px;
text-align:center;
}
.logo p span{
color:lightgreen;
}
.sub a{
color:white;
background:#8F8E8C;
text-decoration:none;
padding:7px 120px;
font-size:13px;
font-family: arial, serif;
font-weight:bold;
-webkit-border-radius:3em;
-moz-border-radius:.1em;
-border-radius:.1em;
}
</style>
<body>
<div class="wrap">
<div class="logo">
<h1>404</h1>
<p>The Page not Found</p>
<div class="sub">
<p><a href="/">Back</a></p>
</div>
</div>
</div>
</body>

View File

@ -0,0 +1,22 @@
async def myOrganization(ns):
"""我的机构
参数:
id:当前登录者id
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
ns['sort'] = 'create_at desc'
ns['del_flg'] = '0'
user = await sor.R('users', ns)
ns['id'] = user[0]['orgid']
reacs = await sor.R('organization', ns)
nss = {'orgid': user[0]['orgid'], 'del_flg': '0'}
userall = await sor.R('users', nss)
if ns.get('uid'):
userall = await sor.R('users', {'id':ns.get('uid')})
return {'status': True, 'dada': reacs, 'users': userall}
return {'status': False, 'msg': '参数错误'}
ret = await myOrganization(params_kw)
return ret

View File

@ -0,0 +1,12 @@
async def upOrganization(ns):
"""修改机构"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
await sor.U('organization', ns)
return {'status': True, 'msg': '修改成功'}
return {'status': False, 'msg': '修改失败'}
ret = await upOrganization(params_kw)
return ret

45
b/README.md Normal file
View File

@ -0,0 +1,45 @@
# gadget
a light wight web server base on aiohttp
## Dependent
* [ahserver](https://github.com/yumoqing/ahserver)
* [sqlor](https://github.com/yumoqing/sqlor) if you want to use database
* [apppublic](https://github.com/yumoqing/apppublic)
## Download
```
git clone git@github.com:yumoqing/gadget.git
```
## Configuration
please look [ahserver](https://github.com/yumoqing/ahserver) to learn how to configure
### support https
under "website" in the conf/config.json file, identify ssl with "crtfile" and "keyfile"
like this.
```
"website":{
"ssl":{
"crtfile":"$[workdir]$/conf/www.bsppo.com.pem",
"keyfile":"$[workdir]$/conf/www.bsppo.com.key"
}
}
```
### log configure
In the conf/config.json, need to config log, you need to identify "name", "levelname" and "logfile"
```
"logger":{
"name":"gadget",
"levelname":"debug",
"logfile":"$[workdir]$/logs/gadget.log"
}
```
## Test
the test folder contains everything need for a base test.
please to go test folder and run
```
python ../src/main.py
```

0
b/__init__.py Normal file
View File

31
b/account/addledgers.dspy Normal file
View File

@ -0,0 +1,31 @@
async def addledgers(ns):
""" 录入客户余额
action: RECHARGE = 充值RECHARGE_REVERSE = 充值冲账
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if not ns.get('apv_id'):
return {'status': False, 'msg': '充值失败'}
if ns.get('apv_id'):
if ns.get('status') != 'agree':
return {'status': False, 'msg': '充值失败'}
apv = await sor.R('apv_data',{'apv_id':ns.get('apv_id')})
balance = float(apv[0]['apv_text'][5:])
date = await get_business_date(sor=None)
recharge_log = {'customerid': apv[0]['result_org'], 'recharge_amt': balance,
'action': 'RECHARGE', 'recharge_path': '2', 'recharge_date': date}
try:
ra = RechargeAccounting(recharge_log)
await ra.accounting(sor)
await sor.C('recharge_log', {'id': uuid(), 'customerid': apv[0]['result_org'],
'recharge_date': datetime.datetime.now().strftime("%Y-%m-%d"),
'recharge_path': '2', 'recharge_amt': balance,
'recharge_timestamp': date, 'action': 'RECHARGE', 'op_userid': apv[0]['apv_sender'],
})
return {'status': True, 'msg': '充值成功'}
except Exception as e:
raise e
return {'status': False, 'msg': '充值失败'}
ret = await addledgers(params_kw)
return ret

120
b/account/email_info.dspy Normal file
View File

@ -0,0 +1,120 @@
# 输入邮件地址,口令和 POP3 服务器地址
email = "billing-specific@kaiyuancloud.cn"
password = "KYY@1234"
# 在对于的邮箱设置的SMTP/POP3里找到对应的服务地址
pop3_server = "pop.qiye.aliyun.com"
# 连接到POP3服务器:
server = poplib.POP3(pop3_server)
# 可以打开或关闭调试信息:
server.set_debuglevel(1)
# 可选:打印POP3服务器的欢迎文字:
print(server.getwelcome().decode('utf-8'))
# 身份认证
server.user(email)
server.pass_(password)
# stat()返回邮件数量和占用空间:
print('邮件数量: %s. 大小: %s' % server.stat())
# list()返回所有邮件的编号:
resp, mails, octets = server.list()
# 获取最新一封邮件, 注意索引号从1开始:
index = len(mails)
resp, lines, octets = server.retr(index)
# lines存储了邮件的原始文本的每一行,
# 可以获得整个邮件的原始文本:
msg_content = b'\r\n'.join(lines).decode('utf-8')
# 稍后解析出邮件,即完成下载邮件
msg = Parser().parsestr(msg_content)
# 接下来解析文件
async def decode_str(s):
value, charset = decode_header(s)[0]
if charset:
value = value.decode(charset)
return value
async def guess_charset(msg):
charset = msg.get_charset()
if charset is None:
content_type = msg.get('Content-Type', '').lower()
pos = content_type.find('charset=')
if pos >= 0:
charset = content_type[pos + 8:].strip()
return charset
# indent用于缩进显示:
async def email_info(msg, indent=0):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if indent == 0:
for header in ['From', 'To', 'Subject']:
value = msg.get(header, '')
if value:
if header=='Subject':
value = await decode_str(value)
else:
hdr, addr = parseaddr(value)
name = await decode_str(hdr)
value = u'%s <%s>' % (name, addr)
print('%s%s: %s' % (' ' * indent, header, value))
if (msg.is_multipart()):
parts = msg.get_payload()
for n, part in enumerate(parts):
print('%spart %s' % (' ' * indent, n))
print('%s--------------------' % (' ' * indent))
await email_info(part, indent + 1)
else:
content_type = msg.get_content_type()
if content_type=='text/plain' or content_type=='text/html':
content = msg.get_payload(decode=True)
charset = await guess_charset(msg)
if charset:
content = content.decode(charset)
try:
#解析交易金额
start_index = content.find("交易金额:") + len("交易金额:")
end_index = content.find("\n", start_index)
find_data = content[start_index:end_index]
price = find_data.strip()[1:]
#解析交易id码
start_index = content.find("摘要:") + len("摘要:")
end_index = content.find("\n", start_index)
find_data = content[start_index:end_index]
index = find_data.index("<")
name = find_data[:index]
if price and name:
mail_code = await sor.R('mail_code',{'mailcode':name,'del_flg':'0'})
date = await get_business_date(sor=None)
recharge_log = {'customerid': mail_code[0]['customer_id'], 'recharge_amt': price,
'action': 'RECHARGE', 'recharge_path': '2', 'recharge_date': date}
try:
ra = RechargeAccounting(recharge_log)
await ra.accounting(sor)
await sor.C('recharge_log', {'id': uuid(), 'customerid': mail_code[0]['customer_id'],
'recharge_date': datetime.datetime.now().strftime("%Y-%m-%d"),
'recharge_path': '2', 'recharge_amt': price,
'recharge_timestamp': date, 'action': 'RECHARGE',
# 'op_userid': apv[0]['apv_sender'],
})
await sor.U('mail_code', {'id': mail_code[0]['id'], 'del_flg': '1'})
return {'status': True, 'msg': '充值成功'}
except Exception as e:
raise e
except:
pass
else:
print('%sAttachment: %s' % (' ' * indent, content_type))
return {"code":'200'}
msg = Parser().parsestr(msg_content)
ret = await email_info(msg)
return ret

View File

@ -0,0 +1,35 @@
async def getrechargelog(ns):
""" 展示我的客户充值记录 """
db = DBPools()
users_id = await get_user()
async with db.sqlorContext('kboss') as sor:
recharge_log = await sor.R('recharge_log',
{'sort': 'create_at desc', 'page': ns['page'], 'op_userid': users_id,
'del_flg': '0'})
if len(recharge_log['rows']) >= 1:
billid = await sor.R('bill', {'sort': 'create_at desc','customerid': recharge_log['rows'][0]['customerid']})
for j in recharge_log['rows']:
RECHARGE_REVERSE = await sor.R('recharge_log',
{'sort': 'create_at desc','del_flg': '0', 'op_userid': users_id, 'original_id': j['id']})
if len(RECHARGE_REVERSE) >= 1:
j['RECHARGE_REVERSE'] = '冲账'
org = await sor.R('organization', {'sort': 'create_at desc','id': j['customerid'], 'del_flg': '0'})
if len(org) >= 1:
j['customerid'] = org[0]['orgname']
j['orgid'] = org[0]['id']
if j['recharge_path'] == '0':
j['recharge_path'] = '支付宝'
elif j['recharge_path'] == '1':
j['recharge_path'] = '微信'
elif j['recharge_path'] == '2':
j['recharge_path'] = '线下充值'
if j['action'] == 'RECHARGE':
j['action'] = '充值'
else:
j['action'] = '充值冲账'
else:
continue
return {'status': True, 'data': recharge_log,'billid':billid}
ret = await getrechargelog(params_kw)
return ret

56
b/account/index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<style type="text/css">
body{
font-family: 'Courgette', cursive;
}
body{
background:#f3f3e1;
}
.wrap{
margin:0 auto;
width:1000px;
}
.logo{
margin-top:50px;
}
.logo h1{
font-size:200px;
color:#8F8E8C;
text-align:center;
margin-bottom:1px;
text-shadow:1px 1px 6px #fff;
}
.logo p{
color:rgb(228, 146, 162);
font-size:20px;
margin-top:1px;
text-align:center;
}
.logo p span{
color:lightgreen;
}
.sub a{
color:white;
background:#8F8E8C;
text-decoration:none;
padding:7px 120px;
font-size:13px;
font-family: arial, serif;
font-weight:bold;
-webkit-border-radius:3em;
-moz-border-radius:.1em;
-border-radius:.1em;
}
</style>
<body>
<div class="wrap">
<div class="logo">
<h1>404</h1>
<p>The Page not Found</p>
<div class="sub">
<p><a href="/">Back</a></p>
</div>
</div>
</div>
</body>

View File

@ -0,0 +1,9 @@
async def openacc(ns):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
accounting_orgid = ns.get('accounting_orgid') #'sBAkKZjSl35T5lr3p9-_1'
orgid = ns.get('orgid') #'wuNnN1VtiwipC_ju1tKOW'
await openProviderAccounts(sor, accounting_orgid, orgid)
return {'code':200}
ret = await openacc(params_kw)
return ret

7
b/account/openacc.dspy Normal file
View File

@ -0,0 +1,7 @@
async def openacc(ns):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
await openOwnerAccounts(sor,'mIWUHBeeDM8mwAFPIQ8pS')
return {'code':200}
ret = await openacc(params_kw)
return ret

View File

@ -0,0 +1,64 @@
async def settle_accounts(ns):
"""供应商结算统计 年、月、日、周、季
0实时结算1:日结2:周结3:月结4:季结5年结
参数id 用户id
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
orgid = await sor.R('users',ns)
account = await sor.R('account', {'id':orgid[0]['orgid']})
if len(account) >= 1:
newdate = await get_business_date(sor=None)
provider = await sor.R('provider',{'orgid':orgid[0]['orgid']})
if provider[0]['settle_mode'] == '1':
date = strdate_add(newdate,-1,0,0)
bill = await sor.R('bill',{'providerid':provider[0]['id'],'bill_date':date})
if len(bill) >= 1:
for i in bill:
org = await sor.R('organization',{'id':i['customerid']})
i['customerid'] = org[0]
elif provider[0]['settle_mode'] == '2':
date = strdate_add(newdate, -7, 0, 0)
nss = {'providerid': provider[0]['id'], 'bill_date': newdate, 'date': date}
sql = """select * from bill where bill_date > ${date}$ and bill_date < ${newdate}$ and providerid = ${providerid}$;"""
bill = await sor.sqlExe(sql,nss)
if len(bill) >= 1:
for i in bill:
org = await sor.R('organization', {'id': i['customerid']})
i['customerid'] = org[0]
elif provider[0]['settle_mode'] == '3':
date = strdate_add(newdate, 0, -1, 0)
nss = {'providerid': provider[0]['id'], 'bill_date': newdate, 'date': date}
sql = """select * from bill where bill_date > ${date}$ and bill_date < ${newdate}$ and providerid = ${providerid}$;"""
bill = await sor.sqlExe(sql, nss)
if len(bill) >= 1:
for i in bill:
org = await sor.R('organization', {'id': i['customerid']})
i['customerid'] = org[0]
elif provider[0]['settle_mode'] == '4':
date = strdate_add(newdate, 0, -3, 0)
nss = {'providerid': provider[0]['id'], 'bill_date': newdate, 'date': date}
sql = """select * from bill where bill_date > ${date}$ and bill_date < ${newdate}$ and providerid = ${providerid}$;"""
bill = await sor.sqlExe(sql, nss)
if len(bill) >= 1:
for i in bill:
org = await sor.R('organization', {'id': i['customerid']})
i['customerid'] = org[0]
elif provider[0]['settle_mode'] == '5':
date = strdate_add(newdate, 0, 0, -1)
nss = {'providerid': provider[0]['id'], 'bill_date': newdate, 'date': date}
sql = """select * from bill where bill_date > ${date}$ and bill_date < ${newdate}$ and providerid = ${providerid}$;"""
bill = await sor.sqlExe(sql, nss)
if len(bill) >= 1:
for i in bill:
org = await sor.R('organization', {'id': i['customerid']})
i['customerid'] = org[0]
return {'status': True, 'data': bill}
except Exception as e:
raise e
return {'status': False, 'msg': '获取失败'}
ret = await settle_accounts(params_kw)
return ret

30
b/account/upledger.dspy Normal file
View File

@ -0,0 +1,30 @@
async def upledger(ns):
""" 客户充值冲账
action: RECHARGE = 充值RECHARGE_REVERSE = 充值冲账
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if not ns.get('apv_id'):
return {'status': False, 'msg': '充值失败'}
if ns.get('apv_id'):
if ns.get('status') != 'agree':
return {'status': False, 'msg': '充值失败'}
apv = await sor.R('apv_data',{'apv_id':ns.get('apv_id')})
balance = float(apv[0]['apv_text'][5:])
date = await get_business_date(sor=None)
recharge_log = {'customerid': apv[0]['result_org'], 'recharge_amt': balance,
'action': 'RECHARGE_REVERSE', 'recharge_path': '2', 'recharge_date': date}
ra = RechargeAccounting(recharge_log)
r = await ra.accounting(sor)
if r == True:
await sor.C('recharge_log', {'id': uuid(), 'customerid': apv[0]['result_org'],'recharge_date': date,
'recharge_path': '2', 'recharge_amt': balance,
'recharge_timestamp': datetime.datetime.now(), 'action': 'RECHARGE_REVERSE',
'original_id': apv[0]['original_id'],
'op_userid': apv[0]['apv_sender']})
return {'status': True, 'msg': '充值冲账成功'}
else:
return {'status': True, 'msg': '充值冲账失败'}
ret = await upledger(params_kw)
return ret

30
b/account/upledgers.dspy Normal file
View File

@ -0,0 +1,30 @@
async def upledgers(ns):
""" 客户充值冲账
action: RECHARGE = 充值RECHARGE_REVERSE = 充值冲账
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if not ns.get('apv_id'):
return {'status': False, 'msg': '充值失败'}
if ns.get('apv_id'):
if ns.get('status') != 'agree':
return {'status': False, 'msg': '充值失败'}
apv = await sor.R('apv_data',{'apv_id':ns.get('apv_id')})
balance = float(apv[0]['apv_text'][7:])
date = await get_business_date(sor=None)
recharge_log = {'customerid': apv[0]['result_org'], 'recharge_amt': balance,
'action': 'RECHARGE_REVERSE', 'recharge_path': '2', 'recharge_date': date}
ra = RechargeAccounting(recharge_log)
r = await ra.accounting(sor)
if r == True:
await sor.C('recharge_log', {'id': uuid(), 'customerid': apv[0]['result_org'],'recharge_date': date,
'recharge_path': '2', 'recharge_amt': balance,
'recharge_timestamp': datetime.datetime.now(), 'action': 'RECHARGE_REVERSE',
'original_id': apv[0]['original_id'],
'op_userid': apv[0]['apv_sender']})
return {'status': True, 'msg': '充值冲账成功'}
else:
return {'status': True, 'msg': '充值冲账失败'}
ret = await upledgers(params_kw)
return ret

247
b/ali/DescribeRegions.dspy Normal file
View File

@ -0,0 +1,247 @@
# -*- coding: utf-8 -*-
# @Time: 2023/8/29 11:06
class KYYAliECS:
def __init__(self):
# self.access_key_id = 'LTAI5tSX7wQnsx6dRfUc3Wfe'
# self.access_key_secret = 'bWiuPh0eCWIaaXXpF9axsPVHX6kWzY'
self.access_key_id = 'LTAI5tGYr9XoLaJD1vBR8Vu7'
self.access_key_secret = 'jbFPoDHinlCOMXhIfQLag9nWX78IMb'
self.sms_client = self.create_client()
def create_client(self):
"""
使用AK&SK初始化账号Client
@param access_key_id:
@param access_key_secret:
@return: Client
@throws Exception
"""
config = open_api_models.Config(
access_key_id=self.access_key_id,
access_key_secret=self.access_key_secret
)
# Endpoint 请参考 https://api.aliyun.com/product/Ecs
config.endpoint = f'ecs-cn-hangzhou.aliyuncs.com'
return Ecs20140526Client(config)
async def get_describe_regions(self, nss):
"""
instance_charge_type
PrePaid包年包月。此时您必须确认自己的账号支持余额支付或者信用支付否则将报错InvalidPayMethod
PostPaid按量付费
SpotWithPriceLimit: 枚举值
默认值为PostPaid。
resource_type:
instanceECS实例
disk磁盘
reservedinstance预留实例券
scu存储容量单位包
默认值instance
accept_language:
zh-CN中文。
en-US英文。
ja日文。
默认值为zh-CN。
:return:
"""
describe_regions_request = ecs_20140526_models.DescribeRegionsRequest(
instance_charge_type=nss.get('instance_charge_type'),
resource_type=nss.get('resource_type'),
accept_language=nss.get('accept_language')
)
runtime = util_models.RuntimeOptions()
resp = await self.sms_client.describe_regions_with_options_async(describe_regions_request, runtime)
# ConsoleClient.log(UtilClient.to_jsonstring(resp))
return UtilClient.to_jsonstring(resp)
async def describe_available_resource(self, ns={}):
describe_available_resource_request = ecs_20140526_models.DescribeAvailableResourceRequest(
region_id=ns.get('region_id'),
memory=ns.get('memory'),
resource_type=ns.get('resource_type'),
scope=ns.get('scope'),
cores=ns.get('cores'),
network_category=ns.get('network_category'),
data_disk_category=ns.get('data_disk_category'),
system_disk_category=ns.get('system_disk_category'),
instance_type=ns.get('instance_type'),
dedicated_host_id=ns.get('dedicated_host_id'),
io_optimized=ns.get('io_optimized'),
zone_id=ns.get('zone_id'),
destination_resource=ns.get('destination_resource'),
spot_duration=ns.get('spot_duration'),
spot_strategy=ns.get('spot_strategy'),
instance_charge_type=ns.get('instance_charge_type')
)
runtime = util_models.RuntimeOptions()
try:
# 复制代码运行请自行打印 API 的返回值
result = await self.sms_client.describe_available_resource_with_options_async(describe_available_resource_request, runtime)
return result
except Exception as error:
# 如有需要,请打印 error
return UtilClient.assert_as_string(error.message)
async def describe_instance_types(self, ns={}):
describe_instance_types_request = ecs_20140526_models.DescribeInstanceTypesRequest(
instance_type_family=ns.get('instance_type_family'),
instance_types=ns.get('instance_types'),
minimum_cpu_core_count=ns.get('minimum_cpu_core_count'),
maximum_cpu_core_count=ns.get('maximum_cpu_core_count'),
minimum_memory_size=ns.get('minimum_memory_size'),
maximum_memory_size=ns.get('maximum_memory_size'),
minimum_gpuamount=ns.get('minimum_gpuamount'),
maximum_gpuamount=ns.get('maximum_gpuamount'),
gpuspec=ns.get('gpuspec'),
instance_category=ns.get('instance_category'),
cpu_architecture=ns.get('cpu_architecture'),
minimum_cpu_speed_frequency=ns.get('minimum_cpu_speed_frequency'),
maximum_cpu_speed_frequency=ns.get('maximum_cpu_speed_frequency'),
minimum_cpu_turbo_frequency=ns.get('minimum_cpu_turbo_frequency'),
maximum_cpu_turbo_frequency=ns.get('maximum_cpu_turbo_frequency'),
physical_processor_model=ns.get('physical_processor_model'),
instance_family_level=ns.get('instance_family_level'),
minimum_instance_pps_rx=ns.get('minimum_instance_pps_rx'),
minimum_instance_pps_tx=ns.get('minimum_instance_pps_tx'),
minimum_instance_bandwidth_rx=ns.get('minimum_instance_bandwidth_rx'),
minimum_instance_bandwidth_tx=ns.get('minimum_instance_bandwidth_tx'),
minimum_primary_eni_queue_number=ns.get('minimum_primary_eni_queue_number'),
minimum_secondary_eni_queue_number=ns.get('minimum_secondary_eni_queue_number'),
minimum_eni_quantity=ns.get('minimum_eni_quantity'),
minimum_queue_pair_number=ns.get('minimum_queue_pair_number'),
minimum_eri_quantity=ns.get('minimum_eri_quantity'),
minimum_eni_private_ip_address_quantity=ns.get('minimum_eni_private_ip_address_quantity'),
minimum_eni_ipv_6address_quantity=ns.get('minimum_eni_ipv_6address_quantity'),
minimum_local_storage_amount=ns.get('minimum_local_storage_amount'),
minimum_local_storage_capacity=ns.get('minimum_local_storage_capacity'),
minimum_disk_quantity=ns.get('minimum_disk_quantity'),
local_storage_category=ns.get('local_storage_category'),
nvme_support=ns.get('nvme_support'),
minimum_baseline_credit=ns.get('minimum_baseline_credit'),
minimum_initial_credit=ns.get('minimum_initial_credit'),
max_results=ns.get('max_results'),
next_token=ns.get('next_token'),
)
runtime = util_models.RuntimeOptions()
try:
# 复制代码运行请自行打印 API 的返回值
result = await self.sms_client.describe_instance_types_with_options_async(describe_instance_types_request, runtime)
return result
except Exception as error:
# 如有需要,请打印 error
return UtilClient.assert_as_string(error.message)
async def describe_price(self, ns={}):
scheduler_options = ecs_20140526_models.DescribePriceRequestSchedulerOptions(
dedicated_host_id='dh-bp67acfmxazb4p****'
)
data_disk_0 = ecs_20140526_models.DescribePriceRequestDataDisk(
category='cloud_ssd',
size=3000,
performance_level='PL1'
)
# 快速购买 默认存在
system_disk = ecs_20140526_models.DescribePriceRequestSystemDisk(
category=ns.get('system_disk').get('category'),
size=ns.get('system_disk').get('size')
)
describe_price_request = ecs_20140526_models.DescribePriceRequest(
region_id=ns.get('region_id'),
resource_type=ns.get('resource_type'),
image_id=ns.get('image_id'),
instance_type=ns.get('instance_type'),
dedicated_host_type=ns.get('dedicated_host_type'),
io_optimized=ns.get('io_optimized'),
instance_network_type=ns.get('instance_network_type'),
internet_charge_type=ns.get('internet_charge_type'),
internet_max_bandwidth_out=ns.get('internet_max_bandwidth_out'),
system_disk=system_disk,
data_disk=ns.get('data_disk'),
period=ns.get('period'),
price_unit=ns.get('price_unit'),
amount=ns.get('amount'),
offering_type=ns.get('offering_type'),
instance_amount=ns.get('instance_amount'),
scope=ns.get('scope'),
platform=ns.get('platform'),
capacity=ns.get('capacity'),
assurance_times=ns.get('assurance_times'),
instance_cpu_core_count=ns.get('instance_cpu_core_count'),
isp=ns.get('isp'),
instance_type_list=ns.get('instance_type_list'),
spot_strategy=ns.get('spot_strategy'),
spot_duration=ns.get('spot_duration'),
zone_id=ns.get('zone_id'),
scheduler_options=ns.get('scheduler_options')
)
runtime = util_models.RuntimeOptions()
try:
result = await self.sms_client.describe_price_with_options_async(describe_price_request, runtime)
return result
except Exception as error:
return UtilClient.assert_as_string(error.message)
async def describe_images(self, ns={}):
describe_images_request = ecs_20140526_models.DescribeImagesRequest(
region_id='cn-qingdao'
# region_id=ns.get('region_id'),
# show_expired=ns.get('show_expired'),
# is_support_io_optimized=ns.get('is_support_io_optimized'),
# is_support_cloudinit=ns.get('is_support_cloudinit'),
# ostype=ns.get('ostype'),
# architecture=ns.get('architecture'),
# usage=ns.get('usage'),
# dry_run=ns.get('dry_run'),
# action_type=ns.get('action_type'),
# resource_group_id=ns.get('resource_group_id'),
# is_public=ns.get('is_public'),
# image_owner_id=ns.get('image_owner_id'),
# page_number=ns.get('page_number'),
# page_size=ns.get('page_size'),
)
runtime = util_models.RuntimeOptions()
try:
result = await self.sms_client.describe_images_with_options_async(describe_images_request, runtime)
return result
except Exception as error:
# 如有需要,请打印 error
return UtilClient.assert_as_string(error.message)
async def DescribeRegions(ns={}):
"""
获取可用区域
:param ns:
:return:
"""
# ns = {
# 'instance_charge_type': 'PrePaid',
# 'resource_type': 'instance',
# 'accept_language': 'zh-CN'
# # 'resource_type': 'disk'
# }
nss = {
'instance_charge_type': ns.get('instance_charge_type'),
'resource_type': ns.get('resource_type'),
'accept_language': ns.get('accept_language')
}
regions = await KYYAliECS().get_describe_regions(nss)
result = json.loads(regions)['body']
result['Regions']['Region_filter'] = {'Asia_China': [], 'Asia_Other': [], 'Europe_America': [], 'Middle_East': []}
for content in result['Regions']['Region']:
if 'cn' in content['RegionId']:
result['Regions']['Region_filter']['Asia_China'].append(content)
elif 'ap' in content['RegionId']:
result['Regions']['Region_filter']['Asia_Other'].append(content)
elif 'en' in content['RegionId'] or 'us' in content['RegionId']:
result['Regions']['Region_filter']['Europe_America'].append(content)
elif 'me' in content['RegionId']:
result['Regions']['Region_filter']['Middle_East'].append(content)
print(result)
return result
ret = await DescribeRegions(params_kw)
return ret

View File

@ -0,0 +1,68 @@
async def product_salemode_search(ns={}):
"""
产品价格不落地
查找sale_protocol以后 具体产品配置查找
:param ns:
:return:
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
if ns.get('salemode') == '0':
res_list = []
ns_search = {
'protocolid': ns.get('protocolid'),
'del_flg': '0'
}
res = await sor.R('product_salemode', ns_search)
# 首先查找不是*的产品 加到产品列表
# 已经存在的id列表
prd_singles = [item.get('productid') for item in res if item.get('productid') != '*']
# 已经存在的id列表 包含对应折扣
prd_single_ids = [(item.get('productid'), item.get('discount')) for item in res if item.get('productid') != '*']
for prd_single in prd_single_ids:
single_sql = """select * from product where id = '%s' and del_flg = '0' and CURRENT_DATE
between effect_date and expire_date;""" % prd_single[0]
single_res_li = await sor.sqlExe(single_sql, {})
single_res = single_res_li[0] if single_res_li else {}
single_res['discount'] = prd_single[1]
res_list.append(single_res)
# 查找*的所有产品id 通过prd_single筛选
nss = {
'productid': '*',
'protocolid': ns.get('protocolid'),
'del_flg': '0'
}
res_star = await sor.R('product_salemode', nss)
if res_star:
# 针对产品设置的统一折扣
start_discount = res_star[0].get('discount')
provider_star = res_star[0].get('providerid')
res_product_sql = """select * from product where providerid = '%s' and del_flg = '0' and CURRENT_DATE
between effect_date and expire_date;""" % provider_star
res_product_li = await sor.sqlExe(res_product_sql, {})
for res_product in res_product_li:
res_product_id = res_product.get('id')
if res_product_id not in prd_singles:
res_product['discount'] = start_discount
res_list.append(res_product)
return {
"status": True,
"msg": "product_salemode search success",
"data": res_list
}
except Exception as e:
return {
"status": False,
"msg": "product_salemode search failed",
'data': e
}
return {
"status": False,
"msg": "product_salemode search failed",
"data": 111,
}
ret = await product_salemode_search(params_kw)
return ret

56
b/ali/index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<style type="text/css">
body{
font-family: 'Courgette', cursive;
}
body{
background:#f3f3e1;
}
.wrap{
margin:0 auto;
width:1000px;
}
.logo{
margin-top:50px;
}
.logo h1{
font-size:200px;
color:#8F8E8C;
text-align:center;
margin-bottom:1px;
text-shadow:1px 1px 6px #fff;
}
.logo p{
color:rgb(228, 146, 162);
font-size:20px;
margin-top:1px;
text-align:center;
}
.logo p span{
color:lightgreen;
}
.sub a{
color:white;
background:#8F8E8C;
text-decoration:none;
padding:7px 120px;
font-size:13px;
font-family: arial, serif;
font-weight:bold;
-webkit-border-radius:3em;
-moz-border-radius:.1em;
-border-radius:.1em;
}
</style>
<body>
<div class="wrap">
<div class="logo">
<h1>404</h1>
<p>The Page not Found</p>
<div class="sub">
<p><a href="/">Back</a></p>
</div>
</div>
</div>
</body>

View File

@ -0,0 +1,73 @@
async def jiajie_get_token_redirect(ns={}):
"""
:param ns:
:return:
"""
# target_host = 'https://testing.vstecscloud.shop'
target_host = 'https://aliyun.kaiyuancloud.cn'
if ns.get('userid'):
userid = ns.get('userid')
else:
userid = await get_user()
password = "weishijiajiekyy"
# 创建一个md5 hash对象
md5_hash = hashlib.md5()
# 对字符串进行编码
md5_hash.update(password.encode('utf-8')) # 注意:需要先将字符串编码为字节串
# 获取十六进制形式的MD5编码
digest = md5_hash.hexdigest()
db = DBPools()
async with db.sqlorContext('kboss') as sor:
username = await sor.R('weishijiajie_users', {'user_id': userid})
if not username:
return {
'status': False,
'msg': '用户未同步'
}
# 构造请求数据
request_data = {
"grant_type": "password",
"scope": "all",
"username": username[0]['jiajie_username'],
"password": digest
}
# 发送HTTP请求
url = "%s/api/blade-auth/oauth/token" % target_host
if 'kaiyuancloud' in target_host:
tenantid = '502332'
else:
tenantid = '024060'
headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Tenant-Id": tenantid,
"Authorization" : "Basic c3dvcmQ6c3dvcmRfc2VjcmV0",
}
method = 'POST'
async with aiohttp_client.request(
method=method,
url=url,
headers=headers,
data=request_data) as res:
result = await res.json()
if result.get('access_token'):
return {
'status': True,
'msg': 'get token success',
'data': target_host + '/kaiyuany/sso?token=' + result.get('access_token')
}
else:
return {
'stauts': False,
'msg': 'get token failed, status: %s, text: %s' % (res.status, result)
}
ret = await jiajie_get_token_redirect(params_kw)
return ret

View File

@ -0,0 +1,78 @@
async def jiajie_sync_user(ns={}):
"""
{'code': 200, 'success': True, 'data': {'userId': '1934862636731187202', 'userName': '68510cdfd558b975a05dc1a5'}, 'msg': '操作成功'}
:param ns:
:return:
"""
if ns.get('userid'):
userid = ns.get('userid')
else:
userid = await get_user()
if not userid:
return {
'status': False,
'msg': '用户还未登录'
}
# target_host = 'https://testing.vstecscloud.shop'
target_host = 'https://aliyun.kaiyuancloud.cn'
db = DBPools()
async with db.sqlorContext('kboss') as sor:
exits_user = await sor.R('weishijiajie_users', {'user_id': userid})
if exits_user:
return {
'status': True,
'msg': 'Synchronized users'
}
userinfos = await sor.R('users', {'id': userid})
phone = userinfos[0]['mobile']
email = userinfos[0]['email']
name = userinfos[0]['username']
# 构造请求数据 筛选条件: 手机号/邮箱
request_data = {
"password": "weishijiajiekyy",
"phone": phone,
"email": email,
"realname": name
}
# 数字信封加密
json_string = json.dumps(request_data)
encrypted_result = await KaiYyEnDecryptUtil.encrypt_by_digital_envelope(json_string)
# 发送HTTP请求
url = '%s/api/blade-user/syncinfo/user/v1' % target_host
method = 'POST'
header = {
"AESKey": encrypted_result["AESKey"]
}
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
data=encrypted_result["data"].encode("utf-8")) as res:
result = await res.json()
# 处理响应
if result.get('success'):
# 正确同步 存库
sync_info = {
'id': uuid(),
'user_id': userid,
'jiajie_userid': result['data']['userId'],
'jiajie_username': result['data']['userName']
}
await sor.C('weishijiajie_users', sync_info)
return {
'status': True,
'msg': 'sync user success'
}
else:
return {
'status': False,
'msg': f"请求失败,状态码: {result.get('code')},响应内容: {result.get('msg')}"
}
ret = await jiajie_sync_user(params_kw)
return ret

View File

@ -0,0 +1,68 @@
async def product_salemode_search(ns={}):
"""
产品价格不落地
查找sale_protocol以后 具体产品配置查找
:param ns:
:return:
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
if ns.get('salemode') == '0':
res_list = []
ns_search = {
'protocolid': ns.get('protocolid'),
'del_flg': '0'
}
res = await sor.R('product_salemode', ns_search)
# 首先查找不是*的产品 加到产品列表
# 已经存在的id列表
prd_singles = [item.get('productid') for item in res if item.get('productid') != '*']
# 已经存在的id列表 包含对应折扣
prd_single_ids = [(item.get('productid'), item.get('discount')) for item in res if item.get('productid') != '*']
for prd_single in prd_single_ids:
single_sql = """select * from product where id = '%s' and del_flg = '0' and CURRENT_DATE
between effect_date and expire_date;""" % prd_single[0]
single_res_li = await sor.sqlExe(single_sql, {})
single_res = single_res_li[0] if single_res_li else {}
single_res['discount'] = prd_single[1]
res_list.append(single_res)
# 查找*的所有产品id 通过prd_single筛选
nss = {
'productid': '*',
'protocolid': ns.get('protocolid'),
'del_flg': '0'
}
res_star = await sor.R('product_salemode', nss)
if res_star:
# 针对产品设置的统一折扣
start_discount = res_star[0].get('discount')
provider_star = res_star[0].get('providerid')
res_product_sql = """select * from product where providerid = '%s' and del_flg = '0' and CURRENT_DATE
between effect_date and expire_date;""" % provider_star
res_product_li = await sor.sqlExe(res_product_sql, {})
for res_product in res_product_li:
res_product_id = res_product.get('id')
if res_product_id not in prd_singles:
res_product['discount'] = start_discount
res_list.append(res_product)
return {
"status": True,
"msg": "product_salemode search success",
"data": res_list
}
except Exception as e:
return {
"status": False,
"msg": "product_salemode search failed",
'data': e
}
return {
"status": False,
"msg": "product_salemode search failed",
"data": 111,
}
ret = await product_salemode_search(params_kw)
return ret

View File

@ -0,0 +1,54 @@
async def appCodesAdd(ns={}):
"""
add new app code
`id` VARCHAR(32) 'id',
`name` VARCHAR(255) '编码名称',
`hierarchy_flg` VARCHAR(1) '多级标志',
`del_flg` VARCHAR(1) DEFAULT '0' comment '删除标志',
`create_at` TIMESTAMP comment '创建时间戳'
:param ns:
:return:
"""
db = DBPools()
# if add kv table and id exists
if ns.get('kv'):
ns['id'] = uuid()
async with db.sqlorContext('kboss') as sor:
try:
await sor.C('appcodes_kv', ns)
return {
"status": True,
"msg": "appcodes_kv add success"
}
except Exception as e:
return {
"status": False,
"msg": "appcodes_kv add failed"
}
app_code = {
'id': ns.get('id'),
'name': ns.get('name'),
'hierarchy_flg': ns.get('hierarchy_flg')
}
async with db.sqlorContext('kboss') as sor:
try:
if not ns.get('id'):
return {
"status": False,
"msg": "app code id is empty"
}
# insert into appcodes
await sor.C('appcodes', app_code)
return {
"status": True,
"msg": "app codes add success"
}
except Exception as e:
return {
"status": False,
"msg": "app codes add failed"
}
ret = await appCodesAdd(params_kw)
return ret

View File

@ -0,0 +1,48 @@
async def appCodesDelete(ns={}):
"""
delete app code
`id` VARCHAR(32) 'id',
`name` VARCHAR(255) '编码名称',
`hierarchy_flg` VARCHAR(1) '多级标志',
`del_flg` VARCHAR(1) DEFAULT '0' comment '删除标志',
`create_at` TIMESTAMP comment '创建时间戳'
:param ns:
:return:
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if not ns.get('id'):
return {
"status": False,
"msg": "appCodes id is empty, please check"
}
if ns.get('kv'):
ns['del_flg'] = '1'
try:
await sor.U('appcodes_kv', ns)
return {
"status": True,
"msg": "appCodes_kv delete success"
}
except Exception as e:
return {
"status": False,
"msg": "appCodes_kv delete failed"
}
try:
ns['del_flg'] = '1'
await sor.U('appcodes',ns)
delete_kv_sql = """update appcodes_kv set del_flg = 1 where codeid = '%s'""" % ns.get('id')
await sor.sqlExe(delete_kv_sql, {})
return {
"status": True,
"msg": "appCodes delete success"
}
except Exception as e:
return {
"status": False,
"msg": "appCodes delete failed"
}
ret = await appCodesDelete(params_kw)
return ret

View File

@ -0,0 +1,43 @@
async def appCodesSearch(ns={}):
"""
search new appcodes
`id` VARCHAR(32) 'id',
`name` VARCHAR(255) '编码名称',
`hierarchy_flg` VARCHAR(1) '多级标志',
`del_flg` VARCHAR(1) DEFAULT '0' comment '删除标志',
`create_at` TIMESTAMP comment '创建时间戳'
:param ns:
:return:
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
ns['del_flg'] = '0'
ns['sort'] = 'create_at'
ns['order'] = 'desc'
ns['page'] = ns.get('page') if ns.get('page') else 1
if ns.get('kv'):
if not ns.get('codeid'):
return {
"status": False,
"msg": "appCodes_kv search failed, the id is empty",
"data": ""
}
app_code_result = await sor.R('appcodes_kv', ns)
else:
app_code_result = await sor.R('appcodes',ns)
return {
"status": True,
"msg": "appCodes search success",
"data": app_code_result
}
except Exception as e:
return {
"status": False,
"msg": "appCodes search failed",
"data": ""
}
ret = await appCodesKvSearch(params_kw)
return ret

View File

@ -0,0 +1,66 @@
async def get_children(parent_id, data):
children = []
for item in data:
if item['parentid'] == parent_id:
child = {'id': item['id'], 'codeid': item['codeid'], 'parentid': item['parentid'], 'k': item['k'], 'v': item['v']}
grandchildren = await get_children(item['id'], data)
if grandchildren:
child['son'] = grandchildren
children.append(child)
return children
async def transform_data(data):
result = []
for item in data:
if item['parentid'] is None or item['parentid'] == '':
parent = {'id': item['id'], 'codeid': item['codeid'], 'parentid': item['parentid'], 'k': item['k'], 'v': item['v']}
children = await get_children(item['id'], data)
if children:
parent['son'] = children
result.append(parent)
return result
async def appCodesSearch(ns={}):
"""
search new appcodes
`id` VARCHAR(32) 'id',
`name` VARCHAR(255) '编码名称',
`hierarchy_flg` VARCHAR(1) '多级标志',
`del_flg` VARCHAR(1) DEFAULT '0' comment '删除标志',
`create_at` TIMESTAMP comment '创建时间戳'
:param ns:
:return:
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
ns['del_flg'] = '0'
ns['sort'] = 'create_at'
ns['order'] = 'desc'
ns['page'] = ns.get('page') if ns.get('page') else 1
if ns.get('kv'):
if not ns.get('codeid'):
return {
"status": False,
"msg": "appCodes_kv search failed, the codeid is empty",
"data": ""
}
app_code_result = await sor.R('appcodes_kv', ns)
app_code_result = await transform_data(app_code_result.get('rows'))
else:
app_code_result = await sor.R('appcodes',ns)
return {
"status": True,
"msg": "appCodes search success",
"data": app_code_result
}
except Exception as e:
return {
"status": False,
"msg": "appCodes search failed",
"data": ""
}
ret = await appCodesSearch(params_kw)
return ret

View File

@ -0,0 +1,46 @@
async def appCodesUpdate(ns={}):
"""
delete app code
`id` VARCHAR(32) 'id',
`name` VARCHAR(255) '编码名称',
`hierarchy_flg` VARCHAR(1) '多级标志',
`del_flg` VARCHAR(1) DEFAULT '0' comment '删除标志',
`create_at` TIMESTAMP comment '创建时间戳'
:param ns:
:return:
"""
ns_appcode = {
'id': ns.get('id'),
'name': ns.get('name'),
'hierarchy_flg': ns.get('hierarchy_flg')
}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
if ns.get('kv'):
try:
await sor.U('appcodes_kv', ns)
return {
"status": True,
"msg": "appcodes_kv update success"
}
except Exception as e:
return {
"status": False,
"msg": "appcodes_kv update failed",
}
await sor.U('appcodes',ns_appcode)
return {
"status": True,
"msg": "appcodes update success",
}
except Exception as e:
return {
"status": False,
"msg": "appcodes update failed",
}
ret = await appCodesUpdate(params_kw)
return ret

6
b/appcode/getTime.dspy Normal file
View File

@ -0,0 +1,6 @@
async def get_server_timestamp(params_kw=None):
return str(int(time.time() * 1000))
ret = await get_server_timestamp(params_kw=1)
return ret

56
b/appcode/index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<style type="text/css">
body{
font-family: 'Courgette', cursive;
}
body{
background:#f3f3e1;
}
.wrap{
margin:0 auto;
width:1000px;
}
.logo{
margin-top:50px;
}
.logo h1{
font-size:200px;
color:#8F8E8C;
text-align:center;
margin-bottom:1px;
text-shadow:1px 1px 6px #fff;
}
.logo p{
color:rgb(228, 146, 162);
font-size:20px;
margin-top:1px;
text-align:center;
}
.logo p span{
color:lightgreen;
}
.sub a{
color:white;
background:#8F8E8C;
text-decoration:none;
padding:7px 120px;
font-size:13px;
font-family: arial, serif;
font-weight:bold;
-webkit-border-radius:3em;
-moz-border-radius:.1em;
-border-radius:.1em;
}
</style>
<body>
<div class="wrap">
<div class="logo">
<h1>404</h1>
<p>The Page not Found</p>
<div class="sub">
<p><a href="/">Back</a></p>
</div>
</div>
</div>
</body>

View File

@ -0,0 +1,291 @@
### 编码增加
请求URL
<http://47.93.12.75:8888/appcode/appCodesAdd.dspy>
请求示例
```
添加Code表
{
'id': 'user_status',
'name': '用户状态',
'hierarchy_flg': '0'
}
添加kv表
{
'kv': '1',
'codeid':'user_status',
'parentid': '123',
'k': '2',
'v': '休息中'
}
```
请求参数说明
添加Code表
| 参数 | 类型 | 必填 | 描述 |
| ------------- | ------ | ---- | --------------------- |
| id | String | 是 | 英文名称例如status |
| name | String | 是 | 中文名称 例如:状态 |
| hierarchy_flg | String | 是 | 多级标志 0/1 是否多级 |
添加kv表
| 参数 | 类型 | 必填 | 描述 |
| -------- | ------ | ---- | -------------- |
| kv | String | 是 | 添加kv表 值为1 |
| codeid | String | 是 | Code表中的id |
| parentid | String | 是 | 父级id |
| k | String | 是 | 键 |
| v | String | 是 | 值 |
返回示例
```
添加成功
{
"status": true,
"msg": "add success"
}
添加失败
{
"status": False,
"msg": "add failed"
}
```
### 编码删除
请求URL
<http://47.93.12.75:8888/appcode/appCodesDelete.dspy>
请求示例
```
删除Code表对应字段
{
'id': 'user_status'
}
添加kv表
{
'kv': '1',
'id': 'kv表中对应id'
}
```
请求参数说明
| 参数 | 类型 | 必填 | 描述 |
| ---- | ------ | ---- | --------------- |
| kv | String | 是 | 删除kv表 值为1 |
| id | String | 是 | Code/kv表中的id |
返回示例
```
删除成功
{
"status": true,
"msg": "appCodes delete success"
}
删除失败
{
"status": False,
"msg": "appCodes delete failed"
}
```
### 编码更新
请求URL
<http://47.93.12.75:8888/appcode/appCodesUpdate.dspy>
请求示例
```
更新Code表
{
'id': 'user_status',
'name': '用户状态',
'hierarchy_flg': '0'
}
更新kv表
{
'kv': '1',
'codeid':'user_status',
'parentid': '123',
'k': '2',
'v': '休息中'
}
```
请求参数说明
更新Code表
| 参数 | 类型 | 必填 | 描述 |
| ------------- | ------ | ---- | --------------------- |
| id | String | 是 | 英文名称例如status |
| name | String | 否 | 中文名称 例如:状态 |
| hierarchy_flg | String | 否 | 多级标志 0/1 是否多级 |
更新kv表
| 参数 | 类型 | 必填 | 描述 |
| -------- | ------ | ---- | -------------- |
| kv | String | 是 | 更新kv表 值为1 |
| codeid | String | 否 | Code表中的id |
| parentid | String | 否 | 父级id |
| k | String | 否 | 键 |
| v | String | 否 | 值 |
返回示例
```
添加成功
{
"status": true,
"msg": "update success"
}
添加失败
{
"status": False,
"msg": "update failed"
}
```
### 编码查询
请求URL
<http://47.93.12.75:8888/appcode/appCodesSearch.dspy>
请求示例
```
查询code表时不需要参数
返回data为[{},{},{}]
查询kv表
{
'kv': '1',
'codeid': 'kv表中对应id'
}
```
请求参数说明
| 参数 | 类型 | 必填 | 描述 |
| ---- | ------ | ----------------- | --------------- |
| kv | String | 否/查询kv为必填项 | 查询kv表 值为1 |
| id | String | 否/查询kv为必填项 | Code/kv表中的id |
返回示例
```
查询成功
{
"status": True,
"msg": "appCodes_kv search success",
"data": app_code_result
}
查询失败
{
"status": False,
"msg": "appCodes_kv search failed",
"data": ""
}
查询成功示例
[
{
"parentid": null,
"k": "0",
"v": "未认证",
"id": "8KxM0iIY",
"codeid": "status"
},
{
"parentid": null,
"k": "1",
"v": "认证",
"id": "GZx0dzSd",
"codeid": "status",
"son": [
{
"parentid": "1",
"k": "0",
"v": "手机号",
"id": "37HmJ8T7",
"codeid": "status",
"son": [
{
"parentid": "1-0",
"k": "0",
"v": "华南地区",
"id": "eVF9aerQ",
"codeid": "status"
},
{
"parentid": "1-0",
"k": "1",
"v": "华中地区",
"id": "j1rhnW6p",
"codeid": "status"
},
{
"parentid": "1-0",
"k": "2",
"v": "华北地区",
"id": "Cr0nWLIU",
"codeid": "status",
"son": [
{
"parentid": "1-0-2",
"k": "0",
"v": "甘肃",
"id": "Gnd5WA4b",
"codeid": "status"
},
{
"parentid": "1-0-2",
"k": "1",
"v": "内蒙古",
"id": "FRHOrEep",
"codeid": "status"
}
]
}
]
},
{
"parentid": "1",
"k": "1",
"v": "微信",
"id": "f1MRJscT",
"codeid": "status"
},
{
"parentid": "1",
"k": "2",
"v": "QQ",
"id": "m3M39BI8",
"codeid": "status"
}
]
}
]
```

View File

@ -0,0 +1,123 @@
编码增加
请求地址: http://47.93.12.75:8888/appcode/appCodesAdd.dspy
请求参数:
`id` VARCHAR(32) 'id',
`name` VARCHAR(255) '编码名称',
`hierarchy_flg` VARCHAR(1) '多级标志',
`del_flg` VARCHAR(1) DEFAULT '0' comment '删除标志',
`create_at` TIMESTAMP comment '创建时间戳'
从code表开始添加 同时添加code_kv表 需要提交的字段
{
'id': '英文字段 例如:user_status',
'name': '中文字段 例如: 用户状态',
'hierarchy_flg': '层级 默认是 0',
# 以下data是同时添加到kv表中的内容
'data':[
{'codeid':'user_status', 'parentid': '123', 'k': '0', 'v': '在线'},
{'codeid':'user_status', 'parentid': '123', 'k': '1', 'v': '未在线'}
]
}
单独添加code_kv表中字段需要提交的字段 kv和codeid为必填项
{'kv': '1', 'codeid':'user_status', 'parentid': '123', 'k': '1', 'v': '休息中'}
响应内容:
增加成功:
{
"status": True,
"msg": "app codes and appcodes_kv add success"
}
增加失败:
{
"status": False,
"msg": "app codes and appcodes_kv add failed"
}
编码删除
请求地址: http://47.93.12.75:8888/appcode/appCodesDelete.dspy
请求参数:
只删除kv表中对应字段对应参数 kv和id为必填项
{'kv': '1', 'id': 'kv表对应id'}
删除code表中字段(同时把kv表对应字段删除) (kv不能为0, 置空或不添加)
{'kv': '', 'id': 'code表中对应id'}
响应内容:
删除成功:
{
"status": True,
"msg": "appCodes delete success"
}
删除失败:
{
"status": False,
"msg": "appCodes delete failed"
}
编码更新
请求地址: http://47.93.12.75:8888/appcode/appCodesUpdate.dspy
请求参数:
只更新kv表中对应字段对应参数 kv和id为必填项
{'kv': '1', 'id': 'J9dAtdLP','codeid':'user_status', 'parentid': '123', 'k': '0', 'v': '在线'}
更新code表中字段(同时把kv表对应字段删除) id为必填项,(kv不能为0, 置空或不添加)
{
'kv': '',
'id': 'user_status',
'name': '客户状态',
'hierarchy_flg': '0'
}
响应内容:
更新成功:
{
"status": True,
"msg": "appcodes update success"
}
更新失败:
{
"status": False,
"msg": "appcodes update failed"
}
编码查询:
请求地址:
查询code:
http://47.93.12.75:8888/appcode/appCodesSearch.dspy
请求参数:
查询code:
查询code表时不需要参数
从code点击字段查询code_kv表: kv必填项 codeid为必填项
{
'kv': '1',
'codeid': 'user_status'
}
响应内容:
查询成功:
{
"status": True,
"msg": "appCodes_kv search success",
"data": app_code_result
}
查询失败:
{
"status": False,
"msg": "appCodes_kv search failed",
"data": ""
}

27
b/apv/apv_business.dspy Normal file
View File

@ -0,0 +1,27 @@
async def apv_business(ns={}):
try:
data = {
"id": ns.get("id", None),
"business_name": ns["business_name"],
"callback_url": ns["callback_url"],
"role_level": ns.get("role_level"),
}
except Exception as e:
return {"status": False, "msg": f"参数解析错误,请检查参数:{e}"}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if data['id']:
data['update_at'] = '{}'.format(datetime.datetime.now())
num = await sor.U("apv_business", data)
if num == 0:
return {"status": False, "msg": "更新失败,数据未更改"}
else:
return {"status": True, "msg": "success"}
else:
data['id'] = uuid()
await sor.C("apv_business", data)
return {"status": True, "msg": "success", "data": data['id']}
ret = await apv_business(params_kw)
return ret

25
b/apv/apv_template.dspy Normal file
View File

@ -0,0 +1,25 @@
async def apv_template(ns={}):
try:
data = {
"id": ns.get("id", None),
"business_id": ns["business_id"],
"title_template": ns["title_template"],
"detail_template": ns["detail_template"],
}
except Exception as e:
return {"status": False, "msg": f"参数解析错误,请检查参数:{e}"}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if data['id']:
data['update_at'] = '{}'.format(datetime.datetime.now())
num = await sor.U("apv_content_template", data)
if num == 0:
return {"status": False, "msg": "更新失败,数据未更改"}
else:
data['id'] = uuid()
await sor.C("apv_content_template", data)
return {"status": True, "msg": "success","data":data['id']}
ret = await apv_template(params_kw)
return ret

233
b/apv/callback_apv.dspy Normal file
View File

@ -0,0 +1,233 @@
class DingCallbackCrypto3:
def __init__(self, token, encodingAesKey, key):
self.encodingAesKey = encodingAesKey
self.key = key
self.token = token
self.aesKey = base64.b64decode(self.encodingAesKey + '=')
## 生成回调处理完成后的success加密数据
def getEncryptedMap(self, content):
encryptContent = self.encrypt(content)
timeStamp = str(int(datetime.datetime.now().timestamp()))
nonce = self.generateRandomKey(16)
sign = self.generateSignature(nonce, timeStamp, self.token, encryptContent)
return {'msg_signature': sign, 'encrypt': encryptContent, 'timeStamp': timeStamp, 'nonce': nonce}
##解密钉钉发送的数据
def getDecryptMsg(self, msg_signature, timeStamp, nonce, content):
"""
解密
:param content:
:return:
"""
sign = self.generateSignature(nonce, timeStamp, self.token, content)
print(sign, msg_signature)
if msg_signature != sign:
raise ValueError('signature check error')
# 对密文BASE64解码
content = base64.decodebytes(content.encode('UTF-8')) ##钉钉返回的消息体
iv = self.aesKey[:16] ##初始向量
aesDecode = AES.new(self.aesKey, AES.MODE_CBC, iv)
decodeRes = aesDecode.decrypt(content)
pad = int(decodeRes[-1])
if pad > 32:
raise ValueError('Input is not padded or padding is corrupt')
decodeRes = decodeRes[:-pad]
l = struct.unpack('!i', decodeRes[16:20])[0]
##获取去除初始向量四位msg长度以及尾部corpid
nl = len(decodeRes)
if decodeRes[(20 + l):].decode() != self.key:
raise ValueError('corpId 钉钉回调校验错误')
return decodeRes[20:(20 + l)].decode()
def encrypt(self, content):
"""
加密
:param content:
:return:
"""
msg_len = self.length(content)
content = ''.join([self.generateRandomKey(16), msg_len.decode(), content, self.key])
contentEncode = self.pks7encode(content)
iv = self.aesKey[:16]
aesEncode = AES.new(self.aesKey, AES.MODE_CBC, iv)
aesEncrypt = aesEncode.encrypt(contentEncode.encode('UTF-8'))
return base64.encodebytes(aesEncrypt).decode('UTF-8')
### 生成回调返回使用的签名值
def generateSignature(self, nonce, timestamp, token, msg_encrypt):
info(f"{type(nonce)=}, {type(timestamp)=}, {type(token)=}, {type(msg_encrypt)=}")
v = msg_encrypt
signList = ''.join(sorted([nonce, timestamp, token, v]))
return hashlib.sha1(signList.encode()).hexdigest()
def length(self, content):
"""
将msg_len转为符合要求的四位字节长度
:param content:
:return:
"""
l = len(content)
return struct.pack('>l', l)
def pks7encode(self, content):
"""
安装 PKCS#7 标准填充字符串
:param text: str
:return: str
"""
l = len(content)
output = io.StringIO()
val = 32 - (l % 32)
for _ in range(val):
output.write('%02x' % val)
# print "pks7encode",content,"pks7encode", val, "pks7encode", output.getvalue()
return content + binascii.unhexlify(output.getvalue()).decode()
def pks7decode(self, content):
nl = len(content)
val = int(binascii.hexlify(content[-1]), 16)
if val > 32:
raise ValueError('Input is not padded or padding is corrupt')
l = nl - val
return content[:l]
def generateRandomKey(self, size,
chars=string.ascii_letters + string.ascii_lowercase + string.ascii_uppercase + string.digits):
"""
生成加密所需要的随机字符串
:param size:
:param chars:
:return:
"""
return ''.join(random.choice(chars) for i in range(size))
async def save_data(apv_id, finis_hTime, apv_status) -> str:
"""
保存审批回调数据
:param apv_id: 审批id
:param finis_hTime: 创建时间
:param apv_status: 流程状态
"""
data = {
"apv_id": apv_id,
"apv_status": apv_status,
"update_at": str(datetime.datetime.now())[:19],
}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
sql = "update apv_data set apv_status = ${apv_status}$ , apv_finish_time=${update_at}$,update_at=${update_at}$ where apv_id = ${apv_id}$"
await sor.sqlExe(sql, data)
data = {
"id": uuid(),
"apv_id": apv_id,
"apv_status": apv_status,
}
await sor.C("apv_status_history", data)
info("数据入库成功")
async def get_key(oid: str) -> str:
db = DBPools()
async with db.sqlorContext('kboss') as sor:
sql = "select http_token,http_aes_key,app_key from apv_key where del_flg = '0' and orgid = ${oid}$"
data = await sor.sqlExe(sql, {"oid": oid})
if data:
return data[0]
else:
raise f"oid:{oid},get key is null."
# 内部回调
async def call_back_inner(processInstanceId, status):
"""
内部回调
:param processInstanceId: apv_id
:param status: 审批状态
:return:
"""
# get callback url
db = DBPools()
async with db.sqlorContext('kboss') as sor:
sql = "SELECT b.callback_url FROM apv_data d LEFT JOIN apv_business b ON d.business_id=b.id WHERE d.apv_id=${processInstanceId}$"
data = await sor.sqlExe(sql, {"processInstanceId": processInstanceId})
if len(data) == 0:
info(f"钉钉内部回调获取失败apv_id:{processInstanceId}")
return 0
data = data[0]
url = data.get("callback_url") + f"?apv_id={processInstanceId}&status={status}"
# url = "https://dev.kaiyuancloud.cn/account/addledgers.dspy?apv_id=ehV03fARQjqtT69piTFtzw07441693812206&status=agree"
async with aiohttp_client.request("GET",url) as res:
try:
json_data = await res.json()
info(f"apv_id:{processInstanceId},回调内部响应:{res.status}resp json:{json_data}")
except Exception as e:
info(f"apv_id:{processInstanceId},回调内部响应:{res.status}resp:{res.text}")
async def get_sender_by_apv_id(apv_id):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
data = await sor.R("apv_data", {"apv_id": apv_id})
if not data:
return None
else:
return data[0]["user_id"]
return None
async def callback_apv(ns={}):
"""
审批回调
:param ns:
:return:
"""
oid = ns.get("oid")
if not oid:
return "oid is None"
data = await get_key(oid)
token = password_decode(data["http_token"])
aes_key = password_decode(data["http_aes_key"])
key = password_decode(data["app_key"])
test = DingCallbackCrypto3(token, aes_key, key)
# 解密参数
text = test.getDecryptMsg(msg_signature=ns.get("signature"), timeStamp=ns.get("timestamp"), nonce=ns.get("nonce"), content=ns.get("encrypt"))
text = json.loads(text)
info(f"回调数据:{text}")
t = text.get("type", None)
if t != "finish":
status = t
else:
status = text.get("result", t)
processInstanceId = text.get("processInstanceId",None)
# 加密返回
res = test.getEncryptedMap("success")
if processInstanceId:
# 判断是否是 api 发起
f = await get_sender_by_apv_id(processInstanceId)
if not f:
info(f"apv_id:{processInstanceId} is not use api")
return res
# 保存数据
await save_data(apv_id=processInstanceId, finis_hTime=text.get("finishTime"), apv_status=status)
try:
# 回调内部接口
info(f"开始回调内部接口:{processInstanceId}")
await call_back_inner(processInstanceId=processInstanceId, status=status)
except Exception as e:
info(f"回调内部接口失败:{e}")
return res
ret = await callback_apv(params_kw)
return ret

View File

@ -0,0 +1,21 @@
async def delete_apv_business(ns={}):
try:
data = {
"id": ns["id"],
"del_flg": ns["del_flg"],
}
except Exception as e:
return {"status": False, "msg": f"参数解析错误,请检查参数:{e}"}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
data['update_at'] = '{}'.format(datetime.datetime.now())
sql = "update apv_business set del_flg = ${del_flg}$,update_at = ${update_at}$ where id = ${id}$ and del_flg = 0"
num = await sor.sqlExe(sql, data)
if num == 0:
return {"status": False, "msg": "删除失败,数据未更改"}
else:
return {"status": True, "msg": "success"}
ret = await delete_apv_business(params_kw)
return ret

View File

@ -0,0 +1,21 @@
async def delete_apv_template(ns={}):
try:
data = {
"id": ns["id"],
"del_flg": ns["del_flg"],
}
except Exception as e:
return {"status": False, "msg": f"参数解析错误,请检查参数:{e}"}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
data['update_at'] = '{}'.format(datetime.datetime.now())
sql = "update apv_content_template set del_flg = ${del_flg}$, update_at = ${update_at}$ where id = ${id}$ and del_flg = 0"
num = await sor.sqlExe(sql, data)
if num == 0:
return {"status": False, "msg": "删除失败,数据未更改"}
else:
return {"status": True, "msg": "success"}
ret = await delete_apv_template(params_kw)
return ret

View File

@ -0,0 +1,14 @@
async def get_apv_business(ns={}):
"""
获取业务列表
"""
ns["del_flg"] = ns.get("del_flg", "0")
ns["sort"] = ns.get("sort", "update_at desc")
db = DBPools()
async with db.sqlorContext('kboss') as sor:
data = await sor.R("apv_business", ns)
return {"status": True, "data": data}
res = await get_apv_business(params_kw)
return res

36
b/apv/get_apv_flow.dspy Normal file
View File

@ -0,0 +1,36 @@
# 获取审批流参数配置
async def get_apv_flow(ns={}):
orgid = ns.get("orgid")
business_id = ns.get("business_id")
if not orgid or not business_id:
return {"status": False, "msg": "orgid or business_id is None"}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
data = await sor.R("apv_flow", {"orgid": orgid, "del_flg": 0, "business_id": business_id})
if not data:
return {"status": True, "data":{}}
flow = {}
flow["orgid"] = data[0]["orgid"]
flow["user_id"] = data[0]["user_id"]
flow["dd_template_id"] = data[0]["dd_template_id"]
flow["del_flg"] = data[0]["del_flg"]
flow["levels"] = {}
for i in data:
l_id = str(i["level"])
now_level = flow["levels"].get(l_id, None)
if now_level:
now_level["apv_dd_user_phone"][i["apv_dd_user_id_index"]] = i["apv_dd_user_phone"]
now_level["mode"] = i["mode"]
else:
user_data = {
"apv_dd_user_phone": {
i["apv_dd_user_id_index"]: i["apv_dd_user_phone"]
},
"mode": i["mode"]
}
flow["levels"][l_id] = user_data
data = flow
return {"status": True, "data": data}
ret = await get_apv_flow(params_kw)
return ret

11
b/apv/get_apv_form.dspy Normal file
View File

@ -0,0 +1,11 @@
# 获取审批表单
async def get_apv_form(ns={}):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
data = await sor.R('apv_form', {'del_flg': '0'})
return {"status": True, "data": data}
return {"status": False, "msg": "sql error"}
ret = await get_apv_form(params_kw)
return ret

21
b/apv/get_apv_key.dspy Normal file
View File

@ -0,0 +1,21 @@
# 获取审批参数配置
async def get_apv_key(ns={}):
orgid = ns.get('orgid')
if not orgid:
return {"status": False, "data": [], "msg": "orgid is null."}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
data = await sor.R('apv_key', {'orgid': orgid, 'del_flg': '0'})
if not data:
return {"status": False, "data": [], "msg": "get key is null."}
data = data[0]
data["app_key"] = password_decode(data["app_key"])
data["app_secret"] = password_decode(data["app_secret"])
data["http_aes_key"] = password_decode(data["http_aes_key"])
data["http_token"] = password_decode(data["http_token"])
return {"status": True, "data": data}
return {"status": False, "data": [], "msg": "sql error"}
ret = await get_apv_key(params_kw)
return ret

14
b/apv/get_apv_list.dspy Normal file
View File

@ -0,0 +1,14 @@
# 获取审批列表
async def get_apv_list(ns={}):
user_id = ns.get("user_id")
if not user_id:
return {"status": False, "msg": "user_id is None"}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
data = await sor.R("apv_data", {"user_id": user_id, "del_flg": 0, "sort": "update_at desc"})
return {"status": True, "data": data}
ret = await get_apv_list(params_kw)
return ret

View File

@ -0,0 +1,17 @@
# 获取审批列表
async def get_apv_template(ns={}):
business_id = ns.get("business_id")
if not business_id:
return {"status": False, "msg": "business_id is None"}
ns["del_flg"] = ns.get("del_flg", "0")
ns["sort"] = ns.get("sort", "update_at desc")
db = DBPools()
async with db.sqlorContext('kboss') as sor:
data = await sor.R("apv_content_template", ns)
return {"status": True, "data": data}
ret = await get_apv_template(params_kw)
return ret

56
b/apv/index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<style type="text/css">
body{
font-family: 'Courgette', cursive;
}
body{
background:#f3f3e1;
}
.wrap{
margin:0 auto;
width:1000px;
}
.logo{
margin-top:50px;
}
.logo h1{
font-size:200px;
color:#8F8E8C;
text-align:center;
margin-bottom:1px;
text-shadow:1px 1px 6px #fff;
}
.logo p{
color:rgb(228, 146, 162);
font-size:20px;
margin-top:1px;
text-align:center;
}
.logo p span{
color:lightgreen;
}
.sub a{
color:white;
background:#8F8E8C;
text-decoration:none;
padding:7px 120px;
font-size:13px;
font-family: arial, serif;
font-weight:bold;
-webkit-border-radius:3em;
-moz-border-radius:.1em;
-border-radius:.1em;
}
</style>
<body>
<div class="wrap">
<div class="logo">
<h1>404</h1>
<p>The Page not Found</p>
<div class="sub">
<p><a href="/">Back</a></p>
</div>
</div>
</div>
</body>

71
b/apv/save_apv_flow.dspy Normal file
View File

@ -0,0 +1,71 @@
async def save_apv_flow(ns={}):
flag = ns.get("flag", "").lower()
if flag not in ["add", "update"]:
return {"status": False, "msg": f"参数解析错误,请检查参数:flag"}
db = DBPools()
try:
async with db.sqlorContext('kboss') as sor:
try:
user_id = ns["user_id"]
orgid = ns["orgid"]
business_id = ns["business_id"]
level_data = ns["level_data"]
except Exception as e:
return {"status": False, "msg": f"参数解析错误,请检查参数:{e}"}
if not isinstance(level_data, list):
return {"status": False, "msg": f"参数类型错误,请检查参数:{level_data}"}
for _f, l in enumerate(level_data):
try:
level_mode = l["level_mode"]
apv_dd_user_phone = l["apv_dd_user_phone"]
except Exception as e:
return {"status": False, "msg": f"参数解析错误,请检查参数:{e}"}
if not isinstance(apv_dd_user_phone, list):
return {"status": False, "msg": f"参数类型错误,请检查参数:{apv_dd_user_phone}"}
if len(apv_dd_user_phone) == 1 and level_mode != "NONE":
return {"status": False, "msg": f"审核模式错误,一个审批人必须为'单人审批'"}
for _f, l in enumerate(level_data):
level_id = l["level_id"]
level_mode = l["level_mode"]
apv_dd_user_phone = l["apv_dd_user_phone"]
for i, p in enumerate(apv_dd_user_phone):
# 通过手机号获取发送人userid
resp = await get_id_by_phone(orgid=orgid, phone=p)
info(f"get_id_by_phone_resp:{resp}")
if not resp['status']:
return {"status": False, "msg": f"钉钉用户id获取失败,请检查手机号:{p}"}
dd_user_id = resp['user_id']
data = {
"user_id": user_id, # '用户id',
"orgid": orgid, # '机构id',
"business_id": business_id, # '业务id',
"level": level_id, # '节点级别',
"mode": level_mode, # 节点审核模式会签AND或签OR单人NONE',
"apv_dd_user_id_index": i, # '节点审核人员id index',
"apv_dd_user_id": dd_user_id, # '节点审核人员id',
"apv_dd_user_phone":p # '节点审核人员手机号',
}
if flag == "update":
if _f == 0 and i == 0:
sql = "update apv_flow set del_flg = 1 ,update_at=${update_at}$ where orgid=${orgid}$ and business_id=${business_id}$"
await sor.sqlExe(sql, {"orgid": orgid, "update_at": f"{datetime.datetime.now()}", "business_id": business_id})
else:
pass
else:
pass
data["id"] = uuid()
await sor.C("apv_flow", data)
return {"status": True, "msg": "保存成功"}
except Exception as e:
return {"status": False, "msg": f"数据库操作失败:{e}"}
return {"status": False, "msg": f"数据库操作失败"}
ret = await save_apv_flow(params_kw)
return ret

31
b/apv/save_apv_key.dspy Normal file
View File

@ -0,0 +1,31 @@
# 保存审批参数配置
async def save_apv_key(ns={}):
_f = ns.get("flag")
try:
data = {
"id": ns.get('id'),
"user_id": ns["user_id"], # 用户id
"orgid": ns["orgid"], # 机构id
"source": ns["source"], # key所属公司
"app_key": password_encode(ns["app_key"]), # 应用凭证key
"app_secret": password_encode(ns["app_secret"]), # 应用凭证secret
"http_aes_key": password_encode(ns["http_aes_key"]), # 加密aes_key
"http_token": password_encode(ns["http_token"]), # 签名token
}
except Exception as e:
return {"status": False, "msg": f"参数解析错误,请检查参数:{e}"}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if _f == "add":
data["id"] = uuid()
await sor.C("apv_key", data)
elif _f == "update":
data["update_time"] = "{}".format(datetime.datetime.now())
await sor.U("apv_key", data)
else:
return {"status": False, "msg": "flag is error"}
return {"status": True, "msg": "success"}
ret = await save_apv_key(params_kw)
return ret

View File

@ -0,0 +1,46 @@
def get_process_code(url):
process_code = url.split('processCode')[-1].replace("%3D", "").replace("=", "")
# if len(process_code) != 41:
# return None
return process_code
# 保存审批参数配置
async def send_key_create(ns={}):
process_code = get_process_code(ns.get("process_code"))
if not process_code:
return {"status": False, "msg": "process_code,参数错误"}
try:
data = {
"id": ns["id"],
"user_id": ns["user_id"], # 用户id
"orgid": ns["orgid"], # 机构id
"send_dd_user_phone": ns["send_phone"], # 发送人的钉钉id
"source": ns["source"], # key所属公司
"business_id": ns["business_id"], # 业务id
"process_code": process_code, # 钉钉审批模板id
"process_name": ns["process_name"], # 钉钉表单名字
}
except Exception as e:
return {"status": False, "msg": f"参数解析错误,请检查参数:{e}"}
# 通过手机号获取发送人userid
resp = await get_id_by_phone(orgid=ns["orgid"], phone=ns["send_phone"])
if not resp['status']:
return {"status": False, "msg": f"{resp['msg']}\n钉钉用户id获取失败,请检查手机号:{ns['send_phone']}"}
data['send_dd_user_id'] = resp['user_id']
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if data['id']:
data["update_time"] = "{}".format(datetime.datetime.now())
await sor.U("apv_send_key", data)
else:
data["id"] = uuid()
await sor.C("apv_send_key", data)
return {"status": True, "msg": "success"}
ret = await send_key_create(params_kw)
return ret

View File

@ -0,0 +1,21 @@
# 获取审批流发送参数配置
async def send_key_select(ns={}):
try:
orgid = ns["orgid"]
business_id = ns["business_id"]
except Exception as e:
return {"status": False, "msg": f"servers get key error, please check key:{str(e)}"}
db = DBPools()
data = {}
async with db.sqlorContext('kboss') as sor:
data = await sor.R("apv_send_key", {"orgid": orgid, "del_flg": 0, "business_id": business_id})
if not data:
return {"status": False, "msg": "未找到发送参数配置"}
data = data[0]
return {"status": True, "data": data}
return {"status": False, "msg": "sql error"}
ret = await send_key_select(params_kw)
return ret

View File

@ -0,0 +1,516 @@
async def user_action_record(ns={}):
ns_dic = {
'id': uuid(),
'source': '百度智能云',
'orderid': ns.get('orderid'),
'ordertype': ns.get('ordertype'),
'userid': ns.get('userid'),
'reason': ns.get('reason')
}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
await sor.C('user_action', ns_dic)
async def time_convert(resoucetime=None):
if not resoucetime:
return
utc_time = datetime.datetime.strptime(resoucetime, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=datetime.timezone.utc)
beijing_time = utc_time.astimezone(datetime.timezone(datetime.timedelta(hours=8)))
return beijing_time.strftime("%Y-%m-%d %H:%M:%S")
async def cal_expire_time(history_time=None, chargeduration=None, unit=None):
chargeduration = int(chargeduration)
# 当前时间
# now = datetime.datetime.now()
now = datetime.datetime.strptime(history_time, '%Y-%m-%d %H:%M:%S')
if unit == 'MONTH':
expire_time = now + dateutil.relativedelta.relativedelta(months=chargeduration)
elif unit == 'YEAR':
expire_time = now + dateutil.relativedelta.relativedelta(years=chargeduration)
else:
expire_time = None
if expire_time:
return str(expire_time)
else:
return None
async def affirmbz_order(ns={}):
"""确认支付"""
order_type = ns.get('order_type')
sor = ns['sor']
orgid = await sor.R('bz_order', {'id': ns['orderid']})
servicename = orgid[0]['servicename']
product_url = None
if ('BCC' in servicename) or ('GPU' in servicename):
product_url = 'https://console.vcp.baidu.com/bcc/#/bcc/instance/list'
date = await get_business_date(sor=None)
# await sor.U('bz_order',{'id':ns['orderid'],'order_date': date})
count = await getCustomerBalance(sor, orgid[0]['customerid'])
if count == None:
count = 0
if count - float(orgid[0]['amount']) < 0:
pricedifference = count - round(orgid[0]['amount'],2)
return {'status': False, 'msg': '账户余额不足','pricedifference': round(pricedifference,2)}
await order2bill(ns['orderid'], sor)
bills = await sor.R('bill', {'orderid': ns['orderid'], 'del_flg': '0'})
try:
# 需要加事务
for i in bills:
ba = BillAccounting(i)
r = await ba.accounting(sor)
dates = datetime.datetime.now()
await sor.U('bz_order', {'id': ns['orderid'], 'order_status': '1','create_at':dates})
await sor.U('bill', {'id': ns['orderid'], 'bill_state': '1'})
order_goods = await sor.R('order_goods', {'orderid': ns['orderid']})
for j in order_goods:
# 处理退订逻辑
if order_type == 'REFUND':
# 找到资源并更新时间
resource_find_sql = """select id from customer_goods where resourceid = '%s';""" % j['resourceids']
resource_find_li = await sor.sqlExe(resource_find_sql, {})
resource_find_id = resource_find_li[0]['id']
await sor.U('customer_goods', {'id': resource_find_id, 'del_flg': '1'})
# 处理续费逻辑
elif order_type == 'RENEW':
# 找到资源并更新时间
resource_find_sql = """select id from customer_goods where resourceid = '%s' and del_flg = '0';""" % j['resourceids']
resource_find_li = await sor.sqlExe(resource_find_sql, {})
resource_find_id = resource_find_li[0]['id']
await sor.U('customer_goods', {'id': resource_find_id, 'start_date': j['resourcestarttime'], 'expire_date': j['resourceendtime']})
# 处理购买逻辑
else:
product = await sor.R('product', {'id': j['productid']})
nss = {}
nss['id'] = uuid()
# nss['id'] = UUID()
nss['providerrid'] = product[0]['providerid']
nss['productname'] = product[0]['name']
nss['productdesc'] = product[0]['description']
nss['customerid'] = orgid[0]['customerid']
nss['productid'] = product[0]['id']
nss['specdataid'] = j['spec_id']
nss['orderid'] = orgid[0]['id']
nss['start_date'] = j['resourcestarttime']
nss['expire_date'] = j['resourceendtime']
nss['resourceid'] = j['resourceids']
if product_url:
nss['product_url'] = product_url
else:
spec = json.loads(product[0]['spec_note']) if isinstance(product[0]['spec_note'], str) else product[0]['spec_note']
spec_list_url = [item['value'] for item in spec if item['configName'] == 'listUrl']
nss['product_url'] = spec_list_url[0] if spec_list_url else 'https://console.vcp.baidu.com/bcc/#/bcc/instance/list'
await sor.C('customer_goods', nss)
return {'status': True, 'msg': '支付成功'}
except Exception as error:
await sor.rollback()
raise error
async def get_baidu_orderlist(ns={}):
"""
百度支付
1、获取订单
2、算出购买的产品折扣
3、比对账号余额
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
baidu_users = await sor.R('baidu_users', {'user_id': ns.get('userid'),'del_flg':'0'})
user = await sor.R('users', {'id': ns.get('userid')})
orgid = await sor.R('organization', {'id': user[0]['orgid']})
nss = {'uuids': [ns.get('order_id')], 'queryAccountId': baidu_users[0]['baidu_id']}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/getByUuid?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com",
"ContentType": "application/json;charset=UTF-8"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=nss) as res:
data_ = await res.json()
orders = data_['orders']
serviceType = orders[0]['orderItems']
# 可能获取得到的是延迟订单
if orders[0]['type'] == 'REFUND' and orders[0]['status'] != 'CREATED':
return {
'status': False,
'msg': 'delay_order'
}
# 避免重复退订
if orders[0]['type'] == 'REFUND' and orders[0]['status'] == 'CREATED':
order_history = await sor.R('bz_order', {'provider_orderid': ns.get('order_id'), 'business_op': 'BUY_REVERSE', 'order_status': '1'})
if order_history:
print('此订单之前已经退费成功')
return {
'status': True,
'msg': '此订单之前已经退费成功'
}
# 如果是退款 更新数据库状态
if orders[0]['type'] == 'REFUND':
updatetime = await time_convert(orders[0]['updateTime']) if orders[0].get('updateTime') else None
update_refund_sql = """UPDATE baidu_orders SET price = '%s', status = '%s', updatetime = '%s' WHERE orderid = '%s';""" % \
(float(orders[0]['price']), orders[0]['status'], updatetime, ns.get('order_id'))
await sor.sqlExe(update_refund_sql, {})
# 判断订单item中productType是否有后付费的产品
for item in orders:
order_items = item['orderItems']
for order_info in order_items:
postpay_price = order_info['itemFee']['price'] if order_info.get('itemFee') else order_info['catalogPrice']
if order_info['productType'] == 'postpay' and postpay_price != 0:
return {
'status': False,
'msg': '暂不支持后付费按量购买, 请联系后台开通'
}
# 实付价格
total_price = 0
productType = ''
# 买/续/退 字段映射
order_type = orders[0]['type']
if order_type == 'NEW':
business_op = 'BUY'
elif order_type == 'RENEW':
business_op = 'RENEW'
elif order_type == 'REFUND':
business_op = 'BUY_REVERSE'
else:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '支付形式目前仅包含购买,续费,退订'
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '线上暂不支持, 请联系售后'
}
try:
# 生成本地订单
bz_ns = {}
bz_ns['id'] = uuid()
bz_ns['order_status'] = '0'
bz_ns['business_op'] = business_op
bz_ns['userid'] = ns.get('userid')
bz_ns['customerid'] = orgid[0]['id']
bz_ns['order_date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
bz_ns['thirdparty_order'] = ns.get('order_id')
bz_ns['source'] = '百度智能云'
bz_ns['originalprice'] = orders[0]['price']
bz_ns['provider_orderid'] = ns.get('order_id')
bz_ns['ordertype'] = orders[0]['productType']
bz_ns['servicename'] = orders[0]['serviceType']
bz_ns['autoreneworder'] = '1' if orders[0]['autoRenewOrder'] else '0'
if ns.get('specdataid'):
bz_ns['specdataid'] = ns['specdataid']
await sor.C('bz_order', bz_ns)
for i in serviceType:
if i['productType'] == 'prepay':
# 预付费
productType = 'prepay'
# financePrice = 0
# 获取产品id
product = await sor.R('product', {'providerpid': 'baidu_' + i['serviceType'], 'del_flg': '0'})
# 获取协议
saleprotocol = await sor.R('saleprotocol',
{'bid_orgid': orgid[0]['id'], 'offer_orgid': orgid[0]['parentid'],
'del_flg': '0'})
if saleprotocol == []:
# 等于空就代表这个客户没有特殊折扣,就要找到买方为*的协议
saleprotocol = await sor.R('saleprotocol', {'bid_orgid': '*', 'offer_orgid': orgid[0]['parentid'],
'del_flg': '0', 'salemode': '0'})
product_salemode = await sor.R('product_salemode',
{'protocolid': saleprotocol[0]['id'], 'productid': product[0]['id'],
'del_flg': '0'})
supply_price = i['itemFee']['price'] if i.get('itemFee') else i['catalogPrice']
financePrice = abs(supply_price * product_salemode[0]['discount'])
total_price += financePrice
# 添加订单子表
nss = {}
nss['id'] = uuid()
nss['orderid'] = bz_ns['id']
nss['productid'] = product[0]['id']
nss['providerid'] = product[0]['providerid']
if i['count'] > 1:
nss['list_price'] = abs(i['realCatalogPrice'] / i['count'])
else:
nss['list_price'] = abs(i['realCatalogPrice'])
nss['discount'] = product_salemode[0]['discount']
nss['quantity'] = i['count']
nss['price'] = abs(round(nss['list_price'] * product_salemode[0]['discount'], 2))
# 计算总价
# nss['amount'] = round(total_price, 2)
nss['amount'] = abs(round(nss['price'] * nss['quantity'], 2))
nss['chargemode'] = i.get('productType')
nss['servicename'] = i.get('serviceType')
nss['chargeduration'] = i.get('time')
nss['unit'] = i.get('timeUnit')
nss['resourceids'] = ','.join(i['shortIds']) if i.get('shortIds') else ''
# 如果是续费订单 由于没有返回日期, 重新计算日期
if order_type == 'RENEW':
history_time_sql = "select resourcestarttime, resourceendtime from order_goods where resourceids = '%s' order by resourceendtime desc;" % \
nss['resourceids']
history_time = await sor.sqlExe(history_time_sql, {})
new_end_time = await cal_expire_time(history_time=history_time[0]['resourceendtime'],
chargeduration=nss['chargeduration'], unit=nss['unit'])
# 开始日期不变 更新到期日期
nss['resourcestarttime'] = history_time[0]['resourcestarttime']
nss['resourceendtime'] = new_end_time
else:
nss['resourcestarttime'] = await time_convert(i.get('resourceStartTime')) if i.get(
'resourceStartTime') else None
nss['resourceendtime'] = await time_convert(i.get('resourceEndTime')) if i.get(
'resourceEndTime') else None
await sor.C('order_goods', nss)
# 循环后更新订单中总价
await sor.U('bz_order', {'id': bz_ns['id'], 'amount': round(total_price, 2)})
except Exception as e:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '发生错误, %s' % str(e)[:100]
}
await user_action_record(ns_record)
import traceback
with open('baiducloud_err.txt', 'w') as f:
f.write(str(e)+ traceback.format_exc())
traceback.print_exc()
# 判断用户账户余额是否足够支付
try:
count = await getCustomerBalance(sor, orgid[0]['id'])
if order_type == 'REFUND':
count = total_price + 0.1
if round(total_price,2) <= count:
#判断预付费或者后付费
if productType == 'prepay':
# 调用扣费接口
affirmbz_order_ns = {
'sor': sor,
'orderid': bz_ns['id'],
'order_type': order_type
}
affirmbz_order_res = await affirmbz_order(affirmbz_order_ns)
if not affirmbz_order_res['status']:
# if True:
await sor.rollback()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '支付错误, 请联系售后'
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '支付错误, 请联系售后'
}
# 预配置local_refund用于本地操作
if order_type == 'REFUND' and not ns.get('local_refund'):
return {
'status': True,
'msg': '本地退费成功'
}
else:
# 调用支付订单接口
# paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderId':ns.get('order_id')}
# ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
# url = 'https://billing.baidubce.com/v1/order/pay?%s' % ns_format
# method = 'POST'
# header = {
# "Host": "billing.baidubce.com"
# }
# header = await get_auth_header(method=method, url=url, header=header)
# async with aiohttp_client.request(
# method=method,
# url=url,
# headers=header,
# json=paydata) as res:
# data_ = await res.json()
# if data_ == {'success': True}:
if True:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '购买成功'
}
await user_action_record(ns_record)
return {
'status': True,
'orderid': bz_ns['id']
}
else:
await sor.rollback()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '支付成功后, order_pay接口错误, 回滚, %s' % str(data_)[:400]
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '产品分配排队中, 请联系售后详询'
}
else:
# 取消订单
await sor.rollback()
paydata = {'queryAccountId': baidu_users[0]['baidu_id'], 'orderIds': [ns.get('order_id')]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '无法购买后付费产品'
}
await user_action_record(ns_record)
return {'status': False, 'msg': '无法购买后付费产品'}
else:
#取消订单
await sor.rollback()
paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderIds':[ns.get('order_id')]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '该账号余额不足,无法完成购买'
}
await user_action_record(ns_record)
return {'status': False,'msg': '该账号余额不足,无法完成购买'}
except Exception as e:
import traceback
with open('baiducloud_err.txt', 'w') as f:
f.write(str(e)+ traceback.format_exc())
traceback.print_exc()
async def baidu_confirm_refund_order(ns={}):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
refund_status_li = await sor.R('baidu_orders', {'orderid': ns.get('order_id')})
refundstatus = refund_status_li[0]['refundstatus']
refund_id = refund_status_li[0]['id']
if not refundstatus:
# data_ = {}
# 调用支付订单接口
paydata = {'queryAccountId': ns.get('baidu_id'), 'orderId':ns.get('order_id')}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/pay?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
data_ = await res.json()
if data_ == {'success': True}:
# if True:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': 'REFUND',
'userid': ns.get('userid'),
'reason': '远程退款成功'
}
await user_action_record(ns_record)
db = DBPools()
async with db.sqlorContext('kboss') as sor:
await sor.U('baidu_orders', {'id': refund_id, 'refundstatus': '1'})
# 增加延迟
import asyncio
await asyncio.sleep(10)
else:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': 'REFUND',
'userid': ns.get('userid'),
'reason': '产品退费失败, %s' % str(data_)[:400]
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '产品退款出错!%s' % str(data_)[:400]
}
if refundstatus == '2':
return {
'status': True,
'msg': '已退款成功'
}
# 获取created状态后再去退款
local_refund_status = await get_baidu_orderlist({'order_id': ns.get('order_id'), 'userid': ns.get('user_id')})
print('local_refund_status', local_refund_status)
if local_refund_status.get('status'):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
await sor.U('baidu_orders', {'id': refund_id, 'refundstatus': '2'})
return {
'status': True,
'msg': '百度云给平台退款成功,平台给客户退款成功'
}
else:
if local_refund_status.get('msg') == 'delay_order':
return {
'status': False,
'msg': '百度远程订单还未生成, 请十秒后重试'
}
return {
'status': False,
'msg': '百度云退款成功,本机构给客户退款出错!'
}
ret = await baidu_confirm_refund_order(params_kw)
return ret

View File

@ -0,0 +1,29 @@
Bag Attributes
friendlyName: caroot
2.16.840.1.113894.746875.1.1: <Unsupported tag 6>
subject=/C=CN/ST=beijing/L=beijing/O=Beijing Baidu Netcom Science Technology Co., Ltd/OU=bms for kafka/CN=baidubce.com/emailAddress=kafka@baidu.com
issuer=/C=CN/ST=beijing/L=beijing/O=Beijing Baidu Netcom Science Technology Co., Ltd/OU=bms for kafka/CN=baidubce.com/emailAddress=kafka@baidu.com
-----BEGIN CERTIFICATE-----
MIID9jCCAt4CCQCoWDtChH/MajANBgkqhkiG9w0BAQsFADCBuzELMAkGA1UEBhMC
Q04xEDAOBgNVBAgMB2JlaWppbmcxEDAOBgNVBAcMB2JlaWppbmcxOTA3BgNVBAoM
MEJlaWppbmcgQmFpZHUgTmV0Y29tIFNjaWVuY2UgVGVjaG5vbG9neSBDby4sIEx0
ZDEWMBQGA1UECwwNYm1zIGZvciBrYWZrYTEVMBMGA1UEAwwMYmFpZHViY2UuY29t
MR4wHAYJKoZIhvcNAQkBFg9rYWZrYUBiYWlkdS5jb20wIBcNMjIwMjA3MDM0MTIw
WhgPMjEyMjAxMTQwMzQxMjBaMIG7MQswCQYDVQQGEwJDTjEQMA4GA1UECAwHYmVp
amluZzEQMA4GA1UEBwwHYmVpamluZzE5MDcGA1UECgwwQmVpamluZyBCYWlkdSBO
ZXRjb20gU2NpZW5jZSBUZWNobm9sb2d5IENvLiwgTHRkMRYwFAYDVQQLDA1ibXMg
Zm9yIGthZmthMRUwEwYDVQQDDAxiYWlkdWJjZS5jb20xHjAcBgkqhkiG9w0BCQEW
D2thZmthQGJhaWR1LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AMAKI035kiy13ECzuHtCXcGybMg2AVsD+auSLHlRncPYB/UaUYM6/eKejEpMgNSk
j/wG+mKmmdt0IY8RUEscOTvVW8TMtpgNib0ALIUWR4CwHjvxJ+y3WV6dqyeUVvIL
CUqeNwFMnC7tEnOutuwEGglQXHjo+zmcPvc9Xk2CdF8SHyaaU1QUoRLJd6qHZ7Xr
/4lC9L+XMrjqzYkXs2dY/2fRbavlOcvETghSavTxKatjpzf7jn/A+s7iYyL9vqQY
Tmm1HVQ2P2ek56uyE4lbiIkMww5r4OIlWKI/OVSAVMKoBt8MOt8DI1o952xyeqMA
NbB8f0Tc1GLm/cGDO2OLmT8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAKA1lULGQ
poYAbskctj8IBwGqSgyZYECP4OeYLgBdev44MMjRgOiDH4H37+69SIJaOql0WnRt
3jrwSznfdjKRZJSzSZ51DcZqBZYP3JfSx/0XG/YwS5yDGo3q8S2DLbcEe8yS7l0q
fo7rnMGeLVTsWwpzXIQZY1Ev4ibcgDm+ZOaEvdK/fqbBQ8sQtavDErVHzkOa3U+C
pL9bBciKXwS6gpsEPeuATtV+fAOzprlKPVTL2n1vVx1zNNlWgSwW2mPof96d+hRI
7aaGF+4luaZ7DC3fxOcIFDmUPA2aJFSs8HnsLV13yvAX3eS8GH0CLgEG+xcXhKYz
7DqKOrjwB+QuWQ==
-----END CERTIFICATE-----

View File

@ -0,0 +1,129 @@
async def time_convert(resoucetime=None):
if not resoucetime:
return
utc_time = datetime.datetime.strptime(resoucetime, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=datetime.timezone.utc)
beijing_time = utc_time.astimezone(datetime.timezone(datetime.timedelta(hours=8)))
return beijing_time.strftime("%Y-%m-%d %H:%M:%S")
async def baidu_new_update_resouce(ns={}):
"""
百度新购订单刷新定时器
用于解决NEED_CONFIRM后订单刷新不及时 不能获取资源ID 资源起始日期的问题
:param ns:
:return:
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
crontab_list = await sor.R('baidu_cron_job', {'source': 'baidu', 'ordertype': 'NEW', 'reason': 'buy success', 'refresh': '0'})
for cronjob in crontab_list:
order_id = cronjob['orderid']
userid = cronjob['userid']
baidu_users = await sor.R('baidu_users', {'user_id': userid,'del_flg':'0'})
# user = await sor.R('users', {'id': userid})
# orgid = await sor.R('organization', {'id': user[0]['orgid']})
nss = {'uuids': [order_id], 'queryAccountId': baidu_users[0]['baidu_id']}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/getByUuid?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com",
"ContentType": "application/json;charset=UTF-8"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=nss) as res:
data_ = await res.json()
with open('baidu_new_order_after_confirm.txt', 'a+') as f:
f.write(json.dumps(data_) + '\n')
orders = data_['orders']
for item in orders:
order_items = item['orderItems']
for order_info in order_items:
resourceids = ','.join(order_info['shortIds']) if order_info.get('shortIds') else ''
if not resourceids:
ns_cron_job = {
'id': cronjob['id'],
'feedback': '没有获取到资源ID'
}
await sor.U('baidu_cron_job', ns_cron_job)
return
resourcestarttime = await time_convert(order_info.get('resourceStartTime')) if order_info.get(
'resourceStartTime') else None
resourceendtime = await time_convert(order_info.get('resourceEndTime')) if order_info.get(
'resourceEndTime') else None
order_key = order_info['key']
if resourceendtime:
update_order_goods_sql = """ UPDATE order_goods og
JOIN bz_order o ON og.orderid = o.id
SET
og.resourceids = '%s',
og.resourcestarttime = '%s',
og.resourceendtime = '%s'
WHERE
og.orderkey = '%s'
AND o.provider_orderid = '%s'; """ \
% (resourceids, resourcestarttime, resourceendtime, order_key, order_id)
else:
update_order_goods_sql = """ UPDATE order_goods og
JOIN bz_order o ON og.orderid = o.id
SET
og.resourceids = '%s',
og.resourcestarttime = '%s'
WHERE
og.orderkey = '%s'
AND o.provider_orderid = '%s'; """ \
% (resourceids, resourcestarttime, order_key, order_id)
await sor.sqlExe(update_order_goods_sql, {})
if resourceendtime:
update_customer_goods_sql = """ UPDATE customer_goods og
JOIN bz_order o ON og.orderid = o.id
SET
og.resourceid = '%s',
og.start_date = '%s',
og.expire_date = '%s'
WHERE
og.orderkey = '%s'
AND o.provider_orderid = '%s'; """ \
% (resourceids, resourcestarttime, resourceendtime, order_key, order_id)
else:
update_customer_goods_sql = """ UPDATE customer_goods og
JOIN bz_order o ON og.orderid = o.id
SET
og.resourceid = '%s',
og.start_date = '%s'
WHERE
og.orderkey = '%s'
AND o.provider_orderid = '%s'; """ \
% (resourceids, resourcestarttime, order_key, order_id)
await sor.sqlExe(update_customer_goods_sql, {})
ns_cron_job = {
'id': cronjob['id'],
'refresh': '1',
'feedback': 'success'
}
await sor.U('baidu_cron_job', ns_cron_job)
return {
'status': True,
'msg': 'update success'
}
return {
'status': True,
'msg': '没有找到需要更新数据'
}
except Exception as e:
return {
'status': False,
'msg': str(e)
}
ret = await baidu_new_update_resouce(params_kw)
return ret

View File

@ -0,0 +1,403 @@
async def user_action_record(ns={}):
ns_dic = {
'id': uuid(),
'source': '百度智能云',
'orderid': ns.get('orderid'),
'ordertype': ns.get('ordertype'),
'userid': ns.get('userid'),
'reason': ns.get('reason')
}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
await sor.C('user_action', ns_dic)
async def time_convert(resoucetime=None):
if not resoucetime:
return
utc_time = datetime.datetime.strptime(resoucetime, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=datetime.timezone.utc)
beijing_time = utc_time.astimezone(datetime.timezone(datetime.timedelta(hours=8)))
return beijing_time.strftime("%Y-%m-%d %H:%M:%S")
async def cal_expire_time(history_time=None, chargeduration=None, unit=None):
chargeduration = int(chargeduration)
# 当前时间
# now = datetime.datetime.now()
now = datetime.datetime.strptime(history_time, '%Y-%m-%d %H:%M:%S')
if unit == 'MONTH':
expire_time = now + dateutil.relativedelta.relativedelta(months=chargeduration)
elif unit == 'YEAR':
expire_time = now + dateutil.relativedelta.relativedelta(years=chargeduration)
else:
expire_time = None
if expire_time:
return str(expire_time)
else:
return None
async def affirmbz_order(ns={}):
"""确认支付"""
order_type = ns.get('order_type')
sor = ns['sor']
orgid = await sor.R('bz_order', {'id': ns['orderid']})
servicename = orgid[0]['servicename']
product_url = None
if ('BCC' in servicename) or ('GPU' in servicename):
product_url = 'https://console.vcp.baidu.com/bcc/#/bcc/instance/list'
date = await get_business_date(sor=None)
await sor.U('bz_order',{'id':ns['orderid'],'order_date': date})
count = await getCustomerBalance(sor, orgid[0]['customerid'])
if count == None:
count = 0
if count - float(orgid[0]['amount']) < 0:
pricedifference = count - round(orgid[0]['amount'],2)
return {'status': False, 'msg': '账户余额不足','pricedifference': round(pricedifference,2)}
await order2bill(ns['orderid'], sor)
bills = await sor.R('bill', {'orderid': ns['orderid'], 'del_flg': '0'})
try:
# 需要加事务
for i in bills:
ba = BillAccounting(i)
r = await ba.accounting(sor)
dates = datetime.datetime.now()
await sor.U('bz_order', {'id': ns['orderid'], 'order_status': '1','create_at':dates})
await sor.U('bill', {'id': ns['orderid'], 'bill_state': '1'})
order_goods = await sor.R('order_goods', {'orderid': ns['orderid']})
for j in order_goods:
# 处理退订逻辑
if order_type == 'REFUND':
# 找到资源并更新时间
resource_find_sql = """select id from customer_goods where resourceid = '%s' and del_flg = '0';""" % j['resourceids']
resource_find_li = await sor.sqlExe(resource_find_sql, {})
resource_find_id = resource_find_li[0]['id']
await sor.U('customer_goods', {'id': resource_find_id, 'del_flg': '1'})
# 处理续费逻辑
elif order_type == 'RENEW':
# 找到资源并更新时间
resource_find_sql = """select id from customer_goods where resourceid = '%s' and del_flg = '0';""" % j['resourceids']
resource_find_li = await sor.sqlExe(resource_find_sql, {})
resource_find_id = resource_find_li[0]['id']
await sor.U('customer_goods', {'id': resource_find_id, 'start_date': j['resourcestarttime'], 'expire_date': j['resourceendtime']})
# 处理购买逻辑
else:
product = await sor.R('product', {'id': j['productid']})
nss = {}
nss['id'] = uuid()
# nss['id'] = UUID()
nss['providerrid'] = product[0]['providerid']
nss['productname'] = product[0]['name']
nss['productdesc'] = product[0]['description']
nss['customerid'] = orgid[0]['customerid']
nss['productid'] = product[0]['id']
nss['specdataid'] = j['spec_id']
nss['orderid'] = orgid[0]['id']
nss['start_date'] = j['resourcestarttime']
nss['expire_date'] = j['resourceendtime']
nss['resourceid'] = j['resourceids']
if product_url:
nss['product_url'] = product_url
else:
spec = json.loads(product[0]['spec_note']) if isinstance(product[0]['spec_note'], str) else product[0]['spec_note']
spec_list_url = [item['value'] for item in spec if item['configName'] == 'listUrl']
nss['product_url'] = spec_list_url[0] if spec_list_url else 'https://console.vcp.baidu.com/bcc/#/bcc/instance/list'
await sor.C('customer_goods', nss)
return {'status': True, 'msg': '支付成功'}
except Exception as error:
raise error
async def baidu_order_process(ns={}):
"""
百度支付
1、获取订单
2、算出购买的产品折扣
3、比对账号余额
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
baidu_users = await sor.R('baidu_users', {'user_id': ns.get('userid'),'del_flg':'0'})
user = await sor.R('users', {'id': ns.get('userid')})
orgid = await sor.R('organization', {'id': user[0]['orgid']})
nss = {'uuids': [ns.get('order_id')], 'queryAccountId': baidu_users[0]['baidu_id']}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/getByUuid?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com",
"ContentType": "application/json;charset=UTF-8"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=nss) as res:
data_ = await res.json()
orders = data_['orders']
serviceType = orders[0]['orderItems']
# 判断订单item中productType是否有后付费的产品
for item in orders:
order_items = item['orderItems']
for order_info in order_items:
if order_info['productType'] == 'postpay' and order_info['itemFee']['price'] != 0:
return {
'status': False,
'msg': '暂不支持后付费按量购买, 请联系后台开通'
}
# 实付价格
total_price = 0
productType = ''
# 买/续/退 字段映射
order_type = orders[0]['type']
if order_type == 'NEW':
business_op = 'BUY'
elif order_type == 'RENEW':
business_op = 'RENEW'
elif order_type == 'REFUND':
business_op = 'BUY_REVERSE'
else:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '支付形式目前仅包含购买,续费,退订'
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '线上暂不支持, 请联系售后'
}
try:
# 生成本地订单
bz_ns = {}
bz_ns['id'] = uuid()
bz_ns['order_status'] = '0'
bz_ns['business_op'] = business_op
bz_ns['userid'] = ns.get('userid')
bz_ns['customerid'] = orgid[0]['id']
bz_ns['order_date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
bz_ns['thirdparty_order'] = ns.get('order_id')
bz_ns['source'] = '百度智能云'
bz_ns['originalprice'] = orders[0]['price']
bz_ns['provider_orderid'] = ns.get('order_id')
bz_ns['ordertype'] = orders[0]['productType']
bz_ns['servicename'] = orders[0]['serviceType']
bz_ns['autoreneworder'] = '1' if orders[0]['autoRenewOrder'] else '0'
if ns.get('specdataid'):
bz_ns['specdataid'] = ns['specdataid']
await sor.C('bz_order', bz_ns)
for i in serviceType:
if i['productType'] == 'prepay':
# 预付费
productType = 'prepay'
# financePrice = 0
# 获取产品id
product = await sor.R('product', {'providerpid': 'baidu_' + i['serviceType'], 'del_flg': '0'})
# 获取协议
saleprotocol = await sor.R('saleprotocol',
{'bid_orgid': orgid[0]['id'], 'offer_orgid': orgid[0]['parentid'],
'del_flg': '0'})
if saleprotocol == []:
# 等于空就代表这个客户没有特殊折扣,就要找到买方为*的协议
saleprotocol = await sor.R('saleprotocol', {'bid_orgid': '*', 'offer_orgid': orgid[0]['parentid'],
'del_flg': '0', 'salemode': '0'})
product_salemode = await sor.R('product_salemode',
{'protocolid': saleprotocol[0]['id'], 'productid': product[0]['id'],
'del_flg': '0'})
supply_price = i['itemFee']['price'] if i.get('itemFee') else i['financePrice']
financePrice = abs(supply_price * product_salemode[0]['discount'])
total_price += financePrice
# 添加订单子表
nss = {}
nss['id'] = uuid()
nss['orderid'] = bz_ns['id']
nss['productid'] = product[0]['id']
nss['providerid'] = product[0]['providerid']
if i['count'] > 1:
nss['list_price'] = abs(i['realCatalogPrice'] / i['count'])
else:
nss['list_price'] = abs(i['realCatalogPrice'])
nss['discount'] = product_salemode[0]['discount']
nss['quantity'] = i['count']
nss['price'] = abs(round(nss['list_price'] * product_salemode[0]['discount'], 2))
# 计算总价
# nss['amount'] = round(total_price, 2)
nss['amount'] = abs(round(nss['price'] * nss['quantity'], 2))
nss['chargemode'] = i.get('productType')
nss['servicename'] = i.get('serviceType')
nss['chargeduration'] = i.get('time')
nss['unit'] = i.get('timeUnit')
nss['resourceids'] = ','.join(i['shortIds']) if i.get('shortIds') else ''
# 如果是续费订单 由于没有返回日期, 重新计算日期
if order_type == 'RENEW':
history_time_sql = "select resourcestarttime, resourceendtime from order_goods where resourceids = '%s' order by resourceendtime desc;" % \
nss['resourceids']
history_time = await sor.sqlExe(history_time_sql, {})
new_end_time = await cal_expire_time(history_time=history_time[0]['resourceendtime'],
chargeduration=nss['chargeduration'], unit=nss['unit'])
# 开始日期不变 更新到期日期
nss['resourcestarttime'] = history_time[0]['resourcestarttime']
nss['resourceendtime'] = new_end_time
else:
nss['resourcestarttime'] = await time_convert(i.get('resourceStartTime')) if i.get(
'resourceStartTime') else None
nss['resourceendtime'] = await time_convert(i.get('resourceEndTime')) if i.get(
'resourceEndTime') else None
await sor.C('order_goods', nss)
# 循环后更新订单中总价
await sor.U('bz_order', {'id': bz_ns['id'], 'amount': round(total_price, 2)})
except Exception as e:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '发生错误, %s' % str(e)[:100]
}
await user_action_record(ns_record)
import traceback
with open('baiducloud_err.txt', 'w') as f:
f.write(str(e)+ traceback.format_exc())
traceback.print_exc()
# 判断用户账户余额是否足够支付
try:
count = await getCustomerBalance(sor, orgid[0]['id'])
if order_type == 'REFUND':
count = total_price + 0.1
if round(total_price,2) <= count:
#判断预付费或者后付费
if productType == 'prepay':
# 调用扣费接口
affirmbz_order_ns = {
'sor': sor,
'orderid': bz_ns['id'],
'order_type': order_type
}
affirmbz_order_res = await affirmbz_order(affirmbz_order_ns)
if not affirmbz_order_res['status']:
# if True:
await sor.rollback()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '支付错误, 请联系售后'
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '支付错误, 请联系售后'
}
# 调用支付订单接口
paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderId':ns.get('order_id')}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/pay?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
data_ = await res.json()
if data_ == {'success': True}:
# if True:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '购买成功'
}
await user_action_record(ns_record)
return {
'status': True,
'orderid': bz_ns['id']
}
else:
await sor.rollback()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '支付成功后, order_pay接口错误, 回滚, %s' % str(data_)[:400]
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '产品分配排队中, 请联系售后详询'
}
else:
# 取消订单
await sor.rollback()
paydata = {'queryAccountId': baidu_users[0]['baidu_id'], 'orderIds': [ns.get('order_id')]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '无法购买后付费产品'
}
await user_action_record(ns_record)
return {'status': False, 'msg': '无法购买后付费产品'}
else:
#取消订单
await sor.rollback()
paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderIds':[ns.get('order_id')]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '该账号余额不足,无法完成购买'
}
await user_action_record(ns_record)
return {'status': False,'msg': '该账号余额不足,无法完成购买'}
except Exception as e:
import traceback
with open('baiducloud_err.txt', 'w') as f:
f.write(str(e)+ traceback.format_exc())
traceback.print_exc()
ret = await baidu_order_process(params_kw)
return ret

View File

@ -0,0 +1,47 @@
async def baidu_resource_query(ns={}):
"""
用户资源查询
:param ns:
:return:
"""
userid = ns.get('userid')
db = DBPools()
async with db.sqlorContext('kboss') as sor:
baiduids = await sor.R('baidu_users', {'user_id': userid})
if baiduids:
baiduid = baiduids[0]['baidu_id']
else:
return {
'status': False,
'msg': 'User not synchronized'
}
ns['queryAccountId'] = baiduid
ns['pageSize'] = 200
method = 'POST'
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/resource/query?%s' % ns_format
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=ns) as res:
result = await res.json()
result_new = []
for i in result['result']:
if i.get('status') != 'STOPPED':
result_new.append(i)
result['result'] = result_new
return {
'status': True,
'msg': 'get resource success',
'data': result
}
ret = await baidu_resource_query(params_kw)
return ret

View File

@ -0,0 +1,152 @@
async def time_convert(resoucetime=None):
if not resoucetime:
return
utc_time = datetime.datetime.strptime(resoucetime, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=datetime.timezone.utc)
beijing_time = utc_time.astimezone(datetime.timezone(datetime.timedelta(hours=8)))
return beijing_time.strftime("%Y-%m-%d %H:%M:%S")
async def baidu_sms_kafka_consumer(ns={}):
consumer = BaiduKafKaConsumer({
# 接入点
'bootstrap.servers': '120.48.10.223:9095,180.76.96.108:9095,180.76.147.36:9095',
# 接入协议
'security.protocol': 'SASL_SSL',
'ssl.endpoint.identification.algorithm': 'none',
# 证书文件路径
'ssl.ca.location': 'baidu_kafka_ca.pem',
# SASL 机制
'sasl.mechanism': 'SCRAM-SHA-512',
# SASL 用户名
'sasl.username': 'kaiyuanyun',
# SASL 用户密码
'sasl.password': 'Kyy250609#',
# 消费组id
'group.id': 'kaiyuanyun_msg_group',
'auto.offset.reset': 'latest',
'fetch.message.max.bytes': '1024*512',
})
# 订阅的主题名称
consumer.subscribe(['kaiyuanyun_msg_topic'])
for i in range(30):
msg = consumer.poll(0.1) # 单次轮询获取消息
if msg is None:
continue
elif msg.error():
print(f"消费者错误: {msg.error()}")
else:
try:
# 解析消息内容为字典(避免变量名冲突)
msg_data_ori = json.loads(msg.value().decode('utf-8'))
msg_data = msg_data_ori['messages'][0]
messageid = msg_data.get('id')
taskid = msg_data.get('taskId')
filename = 'baidu_kafka_msg.txt'
# 检查文件是否存在,不存在则创建
if not os.path.exists(filename):
with open(filename, 'w', encoding='utf-8') as f:
print(f"文件不存在,已创建 {filename}")
# 读取文件内容进行检查
with open(filename, 'r', encoding='utf-8') as f:
content = f.read()
if messageid in content:
print(f"文件中已存在 '{messageid}',跳过写入")
continue
else:
# 追加写入目标内容
with open(filename, 'a', encoding='utf-8') as f:
f.write(messageid + '\n')
print(f"已写入 '{messageid}' 到文件")
db = DBPools()
async with db.sqlorContext('kboss') as sor:
# 1. 去重检查messageid和taskid
exist_msg = await sor.R('baidu_kafka_msg', {'messageid': messageid, 'taskid': taskid})
if exist_msg:
print(f"消息id {messageid} 已存在,跳过处理")
consumer.close()
return
# 2. 构建小写key的ns字典完整映射所有字段
ns_msg = {
'id': uuid(),
'messageid': messageid,
'taskid': taskid,
'userid': msg_data.get('userId'),
'accountid': msg_data.get('accountId'),
'usertype': msg_data.get('userType'),
'receiverid': msg_data.get('receiverId'),
'contentvar': msg_data.get('contentVar'),
'sendchannel': msg_data.get('sendChannel'),
'content': msg_data.get('content'),
'messagetemplateid': msg_data.get('messageTemplateId'),
'isvirtualstore': msg_data.get('isVirtualStore'),
'channelmessageid': msg_data.get('channelMessageId'),
'channelstatus': msg_data.get('channelStatus'),
'majorcategory': msg_data.get('majorCategory'),
'minorcategory': msg_data.get('minorCategory'),
'status': msg_data.get('status'),
'createtime': await time_convert(msg_data.get('createTime')) if msg_data.get('createTime') else None,
'updatetime': await time_convert(msg_data.get('updateTime')) if msg_data.get('updateTime') else None,
'expiretime': await time_convert(msg_data.get('expireTime')) if msg_data.get('expireTime') else None,
'windowtime': await time_convert(msg_data.get('windowTime')) if msg_data.get('windowTime') else None,
'valid': msg_data.get('valid'),
'complete': msg_data.get('complete'),
'disturbhold': msg_data.get('disturbHold'),
'sendcomplete': msg_data.get('sendComplete')
}
# 3. 执行存库
await sor.C('baidu_kafka_msg', ns_msg)
print(f"消息id {messageid} 存储成功")
# 4. 触发短信发送当sendChannel为MOBILE时
send_channel = msg_data.get('sendChannel')
if send_channel == 'MOBILE':
msg_content = msg_data.get('content')
# 判断验证码类短信 | 通知类短信
if '验证码' in msg_content:
sms_stype = '百度kafka普通验证码'
else:
sms_stype = '百度kafka普通通知'
# 查询用户手机号
account_id = msg_data.get('accountId')
user_local_id_li = await sor.R('baidu_users', {'baidu_id': account_id})
user_local_id = user_local_id_li[0]['user_id']
user_mobile_li = await sor.R('users', {'id': user_local_id, 'del_flg': '0'})
mobile = user_mobile_li[0]['mobile']
# 调用短信发送接口
kyy_send_status = await send_vcode(mobile, sms_stype, {'content': msg_content})
if kyy_send_status.get('status'):
await sor.U('baidu_kafka_msg', {'id': ns_msg['id'], 'kyysendstatus': '1'})
print(f"已触发短信发送至 {mobile}")
except json.JSONDecodeError:
print("错误消息内容非有效JSON")
return {
'status': False,
'msg': '错误消息内容非有效JSON'
}
except Exception as e:
print(f"处理异常: {str(e)}")
return {
'status': False,
'msg': f"处理异常: {str(e)}"
}
consumer.close() # 确保消费者关闭
return {
'status': True,
'msg': '获取信息执行结束'
}
ret = await baidu_sms_kafka_consumer(params_kw)
return ret

View File

@ -0,0 +1,666 @@
async def resource_offline(ns={}):
# ns = {
# "accountId": "139fc7a23b314596ad78b6bb8e7c1503",
# "service": "EIP",
# "region": "bj"
# }
method = 'POST'
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/resource/opt/offline?%s' % ns_format
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=ns) as res:
data_ = await res.json()
print('下线返回结果, ', data_)
async def resource_online(ns={}):
# ns = {
# "accountId": "139fc7a23b314596ad78b6bb8e7c1503",
# "service": "EIP",
# "region": "bj"
# }
method = 'POST'
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/resource/opt/online?%s' % ns_format
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=ns) as res:
data_ = await res.json()
print('上线返回结果, ', data_)
async def get_valid_admin_person(nss={}):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
# 查找客户所在的机构
who_is_org = (await sor.R('organization', {'id': nss['customerid']}))[0]['parentid']
# 查找销售的电话
saleman_phone = 0
saleman_id_li = await sor.R('customer', {'customerid': nss['customerid'], 'del_flg': '0'})
if saleman_id_li and saleman_id_li[0]['salemanid']:
saleman_phone_li = await sor.R('users', {'id': saleman_id_li[0]['salemanid']})
if saleman_phone_li and saleman_phone_li[0]['mobile']:
saleman_phone = saleman_phone_li[0]['mobile']
return saleman_id_li[0]['salemanid'], saleman_phone
if (not saleman_phone) or (not saleman_id_li):
# 首先查找运营电话
yunying_mobile = 0
current_yunying_id = await get_role_user_from_org(orgid=who_is_org, role='运营')
if current_yunying_id:
yunying_mobile = (await sor.R('users', {'id': current_yunying_id, 'del_flg': '0'}))[0]['mobile']
if yunying_mobile:
return current_yunying_id, yunying_mobile
if (not yunying_mobile) or (not current_yunying_id):
# 查找管理员电话
current_admin_id = await get_role_user_from_org(orgid=who_is_org, role='管理员')
if current_admin_id:
admin_mobile = (await sor.R('users', {'id': current_admin_id, 'del_flg': '0'}))[0]['mobile']
if admin_mobile:
return current_admin_id, admin_mobile
print('%s 没有找到对应的管理人员进行电话,站内信发送' % nss['customerid'])
return None, None
async def innder_mail_add_msg(nss={}):
"""
:param ns:
:return:
senderid发送人id
receiverid收件人id
msgtitle消息标头
msgtext消息内容
"""
user_orgid = nss['user_orgid']
user_id = nss['userid']
mail_should_send = False
send_type = '欠费通知'
# 记录到欠费表中
# 首先查询欠费表中时间是否再范围内
db = DBPools()
async with db.sqlorContext('kboss') as sor:
customer_name = (await sor.R('organization', {'id': user_orgid}))[0]['orgname']
mail_exist_li = await sor.R('message', {'receiverid': user_id, 'send_type': send_type, 'sort': ['sendtime desc']})
saleman_id, saleman_mobile = await get_valid_admin_person({'customerid': user_orgid})
if mail_exist_li:
# 如果原来发送成功 时间范围大于24小时 再次发送
sms_exist_time = mail_exist_li[0]['sendtime']
time_diff = await get_time_diff(sms_exist_time, time.strftime('%Y-%m-%d %H:%M:%S'))
# 如果发送过的短信在一天范围内 不再发送短信
if time_diff >= 24 * 60:
mail_should_send = True
else:
print('%s 站内信已经发送过, 但是没有超过阈值时间, 不再发送...' % customer_name)
if mail_should_send or not mail_exist_li:
ns_customer = {
'id': uuid(),
'senderid': 'inner',
'receiverid': user_id,
'msgtitle': '系统新消息通知',
'msgtype': '欠费通知',
'msgtext': '尊敬的用户, 您购买的产品 %s 已欠费, 请及时续费以免影响正常使用。' % nss.get('productname'),
}
ns_saleman = {
'id': uuid(),
'senderid': 'inner',
'receiverid': saleman_id,
'msgtitle': '系统新消息通知',
'msgtype': '欠费通知',
'msgtext': '您好, 客户 %s 购买的产品 %s 已欠费, 请及时联系通知。' % (customer_name, nss.get('productname')),
}
await sor.C('message', ns_customer)
await sor.C('message', ns_saleman)
return {'status': True, 'msg': '添加成功'}
async def get_time_diff(time_old=None, time_new=None):
# # 定义两个时间字符串
# time_old = '2023-12-01 09:40:00'
# time_new = '2023-12-01 23:15:00'
# 将时间字符串解析为datetime对象
time_dt1 = datetime.datetime.strptime(time_old, '%Y-%m-%d %H:%M:%S')
time_dt2 = datetime.datetime.strptime(time_new, '%Y-%m-%d %H:%M:%S')
# 计算时间差
time_difference = time_dt2 - time_dt1
# 提取时间差中的分钟数
minutes_difference = time_difference.total_seconds() / 60
# day = time_difference.days
# hour = time_difference.total_seconds() / 3600
return minutes_difference
async def diff_sms_send_save(sor=None, productname=None, time_interval=None, send_type=None, user_orgid=None, sms_send_dict=None):
sms_should_send = False
send_type = send_type
# 记录到欠费表中
# 首先查询欠费表中时间是否再范围内
try:
print('引用发送短信...')
customer_phone = (await sor.R('organization', {'id': user_orgid}))[0]['contactor_phone']
customer_name = (await sor.R('organization', {'id': user_orgid}))[0]['orgname']
sms_exist_li = await sor.R('sms_record', {'mobile': customer_phone, 'send_type': send_type, 'send_status': '1',
'sort': ['send_time desc']})
if sms_exist_li:
# 如果原来发送成功 时间范围大于24小时 再次发送
if sms_exist_li[0]['send_status']:
sms_exist_time = sms_exist_li[0]['send_time']
time_diff = await get_time_diff(sms_exist_time, time.strftime('%Y-%m-%d %H:%M:%S'))
# 如果发送过的短信在一天范围内 不再发送短信
if time_diff >= time_interval:
sms_should_send = True
else:
print('%s %s短信已经发送过, 但是没有超过阈值时间, 不再发送...' % (send_type, customer_phone))
else:
print('%s %s短信没有发送过, 发送...' % (send_type, customer_phone))
sms_should_send = True
if sms_should_send or not sms_exist_li:
# 给个人发送短信
await send_vcode(customer_phone, send_type, sms_send_dict)
# 给相关管理人员发送短信
saleman_id, saleman_mobile = await get_valid_admin_person({'customerid': user_orgid})
if saleman_mobile:
sms_send_dict_saleman = {
'username': customer_name,
'productname': productname
}
if send_type == '用户欠费通知':
print('sms_send_dict_saleman', sms_send_dict_saleman)
await send_vcode(saleman_mobile, '责任人用户欠费通知', sms_send_dict_saleman)
except Exception as e:
print('发送短信失败: %s' % e)
return {
'status': False,
'msg': '发送短信失败',
'data': e
}
async def baidu_post_pay_charge(bill_exist=None, info_detail=None, baidu_orgid=None, userid=None, baidu_id=None, user_orgid=None, user_parentid=None, sor=None):
"""
计算折扣后的价格
获取针对个人的折扣配置
:param ns:
:return:
"""
info_detail_id = info_detail['id']
bill_date = info_detail['starttime']
financeprice = info_detail['catalogprice']
servicetype = info_detail['servicetype']
# utc时间转本地时间
# bill_date_local_time = await utc2local(bill_date)
# 查找对应的产品id
productid_li = await sor.R('product', {'providerid': baidu_orgid, 'providerpid': 'baidu_' + servicetype, 'del_flg': '0'})
if productid_li:
productid_soure = productid_li[0]['id']
product_name = productid_li[0]['name']
else:
productid_soure = None
product_name = None
real_discount = 1.0
person_discount_sql = """select * from saleprotocol where offer_orgid = '%s' and bid_orgid = '%s' and
salemode = '0' and del_flg = '0' and CURRENT_DATE <= end_date and
CURRENT_DATE >= start_date""" % (user_parentid, user_orgid)
tongyi_discount_sql = """select * from saleprotocol where offer_orgid = '%s' and bid_orgid = '*' and
salemode = '0' and del_flg = '0' and CURRENT_DATE <= end_date and
CURRENT_DATE >= start_date""" % user_parentid
# 没有个人配置 获取百度产品统一配置折扣
for sql_detail in [person_discount_sql, tongyi_discount_sql]:
person_discount_li = await sor.sqlExe(sql_detail, {})
for person_discount in person_discount_li:
protocolid = person_discount['id']
xieyi_zi_search_li = await sor.R('product_salemode', {'protocolid': protocolid, 'del_flg': '0'})
for xieyi_zi in xieyi_zi_search_li:
provider_zi_id = xieyi_zi['providerid']
zi_discount = xieyi_zi['discount']
zi_productid = xieyi_zi['productid']
if provider_zi_id == baidu_orgid and zi_productid == productid_soure:
# 判断产品是否存在 有可能在产品表已经删除
prd_res_exists_li = await sor.R('product', {'id': xieyi_zi['productid'], 'del_flg': '0'})
if not prd_res_exists_li:
continue
real_discount = float(zi_discount)
break
if real_discount != 1.0:
break
# 计算实际支付费用
amount = round(real_discount * float(financeprice), 6)
# 根据params表中bussiness_date进行扣费
bussiness_date = (await sor.R('params', {'pname': 'business_date', 'del_flg': '0'}))[0]['pvalue']
nss_bill = {
'id': uuid(),
'customerid': user_orgid,
'business_op': 'BUY',
'provider_amt': financeprice,
'amount': amount,
'bill_date': bussiness_date,
'bill_timestamp': bussiness_date + ' 00:00:00',
'bill_state': 0,
'productid': productid_soure,
'providerid': baidu_orgid,
'quantity': 1
}
# 比对账户余额和账单金额
db_balance = DBPools()
async with db_balance.sqlorContext('kboss') as sor_balance:
balance_yuan = await getCustomerBalance(sor_balance, user_orgid)
print('%s orgid: %s, 余额为: %s' % (time.strftime('%Y-%m-%d %H:%M:%S'), user_orgid, balance_yuan))
print('将要扣除的金额: %s' % nss_bill['amount'])
if balance_yuan < amount:
sms_send_dict = {
'time': time.strftime('%Y-%m-%d %H:') + '00:00',
'productname': product_name
}
db_sms = DBPools()
async with db_sms.sqlorContext('kboss') as sor_sms:
await diff_sms_send_save(sor=sor_sms, productname=product_name, time_interval=24*60, send_type='用户欠费通知', user_orgid=user_orgid, sms_send_dict=sms_send_dict)
await innder_mail_add_msg({'user_orgid': user_orgid, 'userid': userid, 'productname': product_name})
# 查找是否已经存在
exist_qianfei = await sor.R('arrears', {'billid': info_detail['billid']})
if exist_qianfei:
print('%s 欠费账单已经存在...' % info_detail['billid'])
else:
nss_bill['starttime'] = time.strftime('%Y-%m-%d %H:%M:%S')
nss_bill['source'] = '百度智能云'
nss_bill['localid'] = info_detail['id']
nss_bill['billid'] = info_detail['billid']
nss_bill['del_flg'] = 0
await sor.C('arrears', nss_bill)
# 直接创建账单 不再进行扣费再创建账单流程
if not bill_exist:
info_detail['kaiyuanprice'] = amount
await sor.C('baidu_post_bill', info_detail)
print('%s 用户%s 余额不足' % (time.strftime('%Y-%m-%d %H:%M:%S'), user_orgid))
# 产品欠费下线
ns_offline = {
"accountId": baidu_id,
"service": servicetype,
"region": info_detail['region']
}
print('*************', ns_offline)
await resource_offline(ns_offline)
return
# 如果当前余额不足当前账单24小时内支付 发送预警短信
if amount * 24 > balance_yuan:
sms_send_dict = {
'time': time.strftime('%Y-%m-%d %H:') + '00:00',
'balance': int(balance_yuan)
}
dbs = DBPools()
async with dbs.sqlorContext('kboss') as sor_sms:
await diff_sms_send_save(sor=sor_sms, productname=product_name, time_interval=24*60*2, send_type='余额不足提醒', user_orgid=user_orgid, sms_send_dict=sms_send_dict)
# 记账
# 日期 12-06/12-07 凌晨扣费时出错 由于是事务, 12-06/12-07同时出错 无法扣费
# 所以另开事务 至少有一天可以扣费成功
# 扣费不成功的原因:
# business_date和账单日期对不上/acc_balance余额表中所有日期存在大于账单日期
# 余额部分满足时 扣除可用余额后 事务中余额没变化 此处创建新的事务
db_bill = DBPools()
async with db_bill.sqlorContext('kboss') as sor_bill:
try:
ba = BillAccounting(nss_bill)
await ba.accounting(sor_bill)
# 不存在就在此处创建
if not bill_exist:
info_detail['bill_state'] = 1
info_detail['kaiyuanprice'] = amount
await sor_bill.C('baidu_post_bill', info_detail)
# 修改本地bill状态 0:未支付1:已支付2已取消
# 已经存在就更新
ns_bill_status = {
'id': info_detail_id,
'bill_state': 1,
'kaiyuanprice': amount
}
await sor_bill.U('baidu_post_bill', ns_bill_status)
print('百度账单扣费: %s, 扣费成功' % info_detail['billid'])
except Exception as e:
print('用户: %s, 账单: %s, 扣费失败: %s' % (user_orgid, info_detail['billid'], e))
if not bill_exist:
await sor_bill.C('baidu_post_bill', info_detail)
async def save_baidu_post_bill(data_bill, userid=None, baidu_id=None, user_orgid=None, user_parentid=None, sor=None):
try:
# 查找百度orgid 方便一下查找对应产品的productid
baidu_orgid_li = await sor.R('organization', {'orgname': '百度智能云'})
if baidu_orgid_li:
baidu_orgid = baidu_orgid_li[0]['id']
else:
raise ValueError("无法找到百度机构id, 百度供应商名称是: 百度智能云")
# count = 0
for bill_detail in data_bill['bills']:
# count += 1
# if count > 9:
# return
info_detail = {
'id': uuid(),
'billid': bill_detail.get('billId'),
'accountid': data_bill['subAccountId'],
'servicetype': bill_detail.get('serviceType'),
'servicetypename': bill_detail.get('serviceTypeName'),
'producttype': bill_detail.get('productType'),
'region': bill_detail.get('region'),
'instanceid': bill_detail.get('instanceId'),
'shortid': bill_detail.get('shortId'),
'starttime': bill_detail.get('startTime'),
'endtime': bill_detail.get('endTime'),
'configurationch': bill_detail.get('configurationCH'),
'unitprice': bill_detail.get('unitPrice'),
'pricingunit': bill_detail.get('pricingUnit'),
'chargeitem': bill_detail.get('chargeItem'),
'chargeitemdesc': bill_detail.get('chargeItemDesc'),
'amount': bill_detail.get('amount'),
'amountunit': bill_detail.get('amountUnit'),
'discountamount': bill_detail.get('discountAmount'),
'originprice': bill_detail.get('originPrice'),
'catalogprice': bill_detail.get('catalogPrice'),
'financeprice': bill_detail.get('financePrice'),
'couponprice': bill_detail.get('couponPrice'),
'discountcouponprice': bill_detail.get('discountCouponPrice'),
'cashequivalentcouponprice': bill_detail.get('cashEquivalentCouponPrice'),
'discountprice': bill_detail.get('discountPrice'),
'sysgold': bill_detail.get('sysGold'),
'deductprice': bill_detail.get('deductPrice'),
'originconfig': json.dumps(bill_detail),
'bill_state': 0,
'del_flg': '0'
}
db_sor_bill = DBPools()
async with db_sor_bill.sqlorContext('kboss') as sor_find_bill:
exist_bill_id = await sor_find_bill.R('baidu_post_bill', {'billid': info_detail['billid']})
bill_exist = 0
if exist_bill_id:
if exist_bill_id[0]['bill_state'] == '0':
print('%s 百度后付费账单已经存在, 没有扣款, 账单号: %s' % (user_orgid, info_detail['billid']))
# 此时id已经存在 不再生成新的id
info_detail['id'] = exist_bill_id[0]['id']
bill_exist = 1
else:
# print('%s 百度后付费账单已经存在, 已经扣款, 账单号: %s' % (user_orgid, info_detail['billid']))
continue
else:
pass
# 数据库同时插入和更新死锁 此处不再插入
# await sor.C('baidu_post_bill', info_detail)
# 扣费
await baidu_post_pay_charge(bill_exist=bill_exist, info_detail=info_detail, baidu_orgid=baidu_orgid, userid=userid, baidu_id=baidu_id, user_orgid=user_orgid, user_parentid=user_parentid, sor=sor)
except Exception as e:
print('save_baidu_post_bill: %s' % e)
raise e
async def get_auth_header(method: str, url: str, header: dict, query={}, get_res=False):
import urllib
import hmac
AK = 'ALTAKPk92fX9cgGDax83yNL8mP'
SK = '9b16b8efd4dc463d8bbd5462db1db8a5'
# 解析uri
url_parse = urllib.parse.urlparse(url)
uri = url_parse.path
url_query = url_parse.query
# 获取query
if url_query:
query = dict(urllib.parse.parse_qsl(url_query))
# 2.x-bce-date
x_bce_date = time.gmtime()
x_bce_date = time.strftime('%Y-%m-%dT%H:%M:%SZ', x_bce_date)
# 4.认证字符串前缀
authStringPrefix = "bce-auth-v1" + "/" + AK + "/" + x_bce_date + "/" + "1800"
# windows下为urllib.parse.quoteLinux下为urllib.quote
# 5.生成CanonicalRequest
# 5.1生成CanonicalURI
CanonicalURI = urllib.parse.quote(uri)
# 如果您调用的接口的query比较复杂的话需要做额外处理
# 5.2生成CanonicalQueryString
# CanonicalQueryString = query
result = ['%s=%s' % (k, urllib.parse.quote(str(v))) for k, v in query.items() if k.lower != 'authorization']
result.sort()
CanonicalQueryString = '&'.join(result)
# 5.3生成CanonicalHeaders
result = []
signedHeaders_list = []
for key,value in header.items():
tempStr = str(urllib.parse.quote(key.lower(),safe="")) + ":" + str(urllib.parse.quote(value,safe=""))
signedHeaders_list.append(str(urllib.parse.quote(key.lower(),safe="")))
result.append(tempStr)
result.sort()
signedHeaders = ';'.join(sorted(signedHeaders_list))
CanonicalHeaders = "\n".join(result)
# 5.4拼接得到CanonicalRequest
CanonicalRequest = method + "\n" + CanonicalURI + "\n" + CanonicalQueryString +"\n" + CanonicalHeaders
# 6.生成signingKey
signingKey = hmac.new(SK.encode('utf-8'), authStringPrefix.encode('utf-8'), hashlib.sha256)
# 7.生成Signature
Signature = hmac.new((signingKey.hexdigest()).encode('utf-8'), CanonicalRequest.encode('utf-8'), hashlib.sha256)
# 8.生成Authorization并放到header里
header['Authorization'] = authStringPrefix + "/" + signedHeaders + "/" + Signature.hexdigest()
if get_res:
# 异步请求链接 返回结果
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
allow_redirects=True,
json=query) as res:
return res
else:
return header
async def arrears_charge(customerid=None, source=None):
"""
优先扣除欠费表中的账单
:param ns:
:return:
"""
# customerid = 'gKG8UaYPjA_29K7puzaTM'
# source = '百度智能云'
db_arrears = DBPools()
async with db_arrears.sqlorContext('kboss') as sor_arrears:
bill_date = (await sor_arrears.R('params', {'pname': 'business_date', 'del_flg': '0'}))[0]['pvalue']
try:
arrear_li = await sor_arrears.R('arrears', {'source': source, 'customerid': customerid, 'bill_state': '0'})
arrear_product_types = []
for arr in arrear_li:
nss_bill = {
'id': uuid(),
'customerid': arr['customerid'],
'business_op': arr['business_op'],
'provider_amt': arr['provider_amt'],
'amount': arr['amount'],
'bill_date': bill_date,
'bill_timestamp': bill_date + ' 00:00:00',
'bill_state': 0,
'productid': arr['productid'],
'providerid': arr['providerid'],
'quantity': arr['quantity']
}
ba = BillAccounting(nss_bill)
await ba.accounting(sor_arrears)
# 修改本地bill状态 0:未支付1:已支付2已取消
# 已经存在就更新
arrear_status = {
'id': arr['id'],
'bill_state': 1,
'endtime': time.strftime('%Y-%m-%d %H:%M:%S')
}
await sor_arrears.U('arrears', arrear_status)
print('%s 百度账单-欠费账单-扣费成功, 状态更新成功: %s' % (arr['customerid'], arr['id']))
baidu_post_bill_status = {
'id': arr['localid'],
'bill_state': 1
}
await sor_arrears.U('baidu_post_bill', baidu_post_bill_status)
print('%s 百度账单-欠费账单扣费成功---本地账单-更新成功, 状态更新成功: %s' % (arr['customerid'], arr['billid']))
# 获取百度下线类型列表 用于产品上线
products = await sor_arrears.R('baidu_post_bill', {'id': arr['localid']})
ns_type = {
"accountId": products[0]['accountid'],
"service": products[0]['servicetype'],
"region": products[0]['region']
}
arrear_product_types.append(ns_type)
return {
'status': True,
'data': [dict(t) for t in {frozenset(d.items()) for d in arrear_product_types}]
}
except Exception as e:
print('用户: %s, 欠费账单扣费失败: %s' % (customerid, e))
return {
'status': False
}
async def get_resourcechargeitem_billlist(userid=None, baidu_id=None, user_orgid=None, user_parentid=None, pageno=1, sor=None):
"""
分页获取后付费资源计费项账单详情, 颗粒度:小时 不能查看当月账单
1. 账单过来后余额充足正常扣费
1048条扣费前余额:18327.51 扣费后余额: 18267.13 实际扣除:60.38 实际账单应扣除总额: 62.4347
前10条: 扣费前余额:18267.13 扣费后余额: 18266.93 实际扣除:0.2 实际账单应扣除总额: 0.2255
2. 账单过来后余额不足短信通知
2.1 账单过来后余额不足短信通知-时间范围内是否重复发送
2.1.1 重复发送 创建一个单独事务 修复
2.1.2 充值-但只足够部分账单扣费 余额查询创建单独事务 修复
2.2 账单过来后余额不足短信通知-超过时间范围是否发送 正常发送
2.3 是否在欠费账单里
2.3.1 后续还在欠费 是否在欠费账单重复 不重复
2.3.2 后续余额充足 是否把欠费补充完成 是
3. 余额充足 3个账单 正常扣费 balance由于是小数点两位 造成误差
余额充足 但是不够24小时费用 正常扣费 客户短信正常发送 销售短信发送失败productname=None 修复
余额部分满足 正常扣费 短信不能正常发送/post_bill kaiyuanprice为空没有正常录入 创建新事务 修复
欠费表已存在 重复请求是否重复 不重复
欠费表已存在 余额充足 是否正常扣费 欠费表和post_bill表重复扣费 欠费表创建单独的事务 在查询存在账单时创建事务 修复
欠费表单独事务 - 每一次欠费项一个事务 否则造成欠费表同时不成功 但post_bill表反而扣费成功了 造成不同步 (测试发现状态可以正常改变)
存在问题 1. 小数点过小无法扣除 实际扣除0.0 应扣除0.0205
2. import urllib hmac
3. accounting.bill.BillAccounting 线上删除accounting.bill 此处报错 但账单已保存 测试
:param ns:
:return:
"""
# 优先扣除欠费信息 欠费表/取消释放/忽略小数点后几位较小误差
arrear_types = await arrears_charge(customerid=user_orgid, source='百度智能云')
# 扣费成功 开启下线的服务
if arrear_types and arrear_types.get('status') and arrear_types.get('data'):
for roline in arrear_types['data']:
await resource_online(roline)
# 获取当前日期和时间
current_time = datetime.datetime.now()
# 指定开始日期
# date_string = "2023-11-30"
# format = '%Y-%m-%d' # specifify the format of the date_string.
# current_time = datetime.datetime.strptime(date_string, format)
# 计算七天前的日期
days_ago = current_time - datetime.timedelta(days=7)
# 获取账单百度指定必须在同一个月内
if current_time.month != days_ago.month:
days_ago = datetime.datetime(current_time.year, current_time.month, 1)
# 将日期时间格式化为字符串
current_day = current_time.strftime("%Y-%m-%d")
days_ago_time = days_ago.strftime("%Y-%m-%d")
ns = {
"beginTime": days_ago_time,
"endTime": current_day,
"queryAccountId" : baidu_id,
"pageNo": pageno,
"pageSize": 100
}
method = 'POST'
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/bill/resource/chargeitem?%s' % ns_format
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=ns) as res:
data_bill = await res.json()
if data_bill.get('bills'):
await save_baidu_post_bill(data_bill=data_bill, userid=userid, baidu_id=baidu_id, user_orgid=user_orgid, user_parentid=user_parentid, sor=sor)
real_page_no = int(data_bill['totalCount'] / data_bill['pageSize']) + 1
if data_bill['pageNo'] < real_page_no:
await get_resourcechargeitem_billlist(userid=userid, baidu_id=baidu_id, user_orgid=user_orgid, user_parentid=user_parentid, pageno=data_bill['pageNo'] + 1, sor=sor)
else:
print('%s 账号ID: %s 后付费账单同步成功, 同步页面数量: %s' % (current_time.strftime("%Y-%m-%d %H:%M:%S"), data_bill['subAccountId'], data_bill['pageNo']))
else:
print('%s 账号ID: %s 或空bills, 后付费账单同步成功, 同步页面数量: %s' % (
current_time.strftime("%Y-%m-%d %H:%M:%S"), data_bill['subAccountId'], data_bill['pageNo']))
async def baidu_users_get_post_pay(ns={}):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
# 获取所有百度用户
baidu_users = await sor.R('baidu_users', {'del_flg': '0'})
for baidu_user in baidu_users:
userid = baidu_user['user_id']
baidu_id = baidu_user['baidu_id']
# if baidu_id != 'dcf0fa1519d24de893b186e52d733bd2':
# continue
try:
user_orgid = (await sor.R('users', {'id': userid}))[0]['orgid']
user_parentid = (await sor.R('organization', {'id': user_orgid}))[0]['parentid']
await get_resourcechargeitem_billlist(userid=userid, baidu_id=baidu_id, user_orgid=user_orgid, user_parentid=user_parentid, pageno=1, sor=sor)
except Exception as e:
return {
'status': False,
'msg': '百度后付费账单发生错误',
'data': e
}
return {
'status': True,
'msg': '百度账户后付费扣费成功...'
}
ret = await baidu_users_get_post_pay(params_kw)
return ret

View File

@ -0,0 +1,22 @@
async def get_baidu_users_base_org(ns={}):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns.get('user_id_or_name'):
user_find_sql = """ SELECT DISTINCT b.user_id, u.username FROM organization o INNER JOIN users u ON o.id = u.orgid INNER JOIN baidu_users b ON u.id = b.user_id WHERE o.parentid = '%s' AND b.del_flg = '0' AND (b.user_id = '%s' OR u.username = '%s'); """ % (ns['orgid'], ns['user_id_or_name'], ns['user_id_or_name'])
user_find_li = await sor.sqlExe(user_find_sql, {})
return {
'status': True,
'msg': 'search user success',
'data': user_find_li
}
else:
user_find_sql = """ SELECT DISTINCT b.user_id, u.username FROM organization o INNER JOIN users u ON o.id = u.orgid INNER JOIN baidu_users b ON u.id = b.user_id WHERE o.parentid = '%s' AND b.del_flg = '0'; """ % ns['orgid']
user_find_li = await sor.sqlExe(user_find_sql, {})
return {
'status': True,
'msg': 'search user success',
'data': user_find_li
}
ret = await get_baidu_users_base_org(params_kw)
return ret

View File

@ -0,0 +1,45 @@
async def get_local_baidu_orders(ns={}):
order_page_size = int(ns['pageSize']) if ns.get('pageSize') else 20
order_page_offset = (int(ns['pageNo']) - 1) * order_page_size if ns.get('pageNo') else 0
ordertype = ns.get('ordertype')
servicetype = ns.get('servicetype')
producttype = ns.get('producttype')
status = ns.get('status')
autoreneworder = ns.get('autoreneworder')
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns.get('user_id_or_name'):
orders_find_sql = """ SELECT u.username, bs.user_id, bo.* FROM baidu_orders bo INNER JOIN baidu_users bs ON bs.baidu_id = bo.accountid INNER JOIN users u ON bs.user_id = u.id WHERE (bs.user_id = '%s' OR u.username = '%s') AND bo.del_flg = '0'""" % (ns.get('user_id_or_name'), ns.get('user_id_or_name'))
else:
orders_find_sql = """ SELECT u.username, bs.user_id, bo.* FROM baidu_orders bo INNER JOIN baidu_users bs ON bs.baidu_id = bo.accountid INNER JOIN users u ON bs.user_id = u.id WHERE bo.del_flg = '0'"""
if ordertype:
orders_find_sql += """ AND ordertype = '%s' """ % ordertype
if servicetype:
orders_find_sql += """ AND servicetype = '%s' """ % servicetype
if producttype:
orders_find_sql += """ AND producttype = '%s' """ % producttype
if status:
orders_find_sql += """ AND status = '%s' """ % status
if autoreneworder:
orders_find_sql += """ AND autoreneworder = '%s' """ % autoreneworder
count_num_li = await sor.sqlExe(orders_find_sql, {})
count_num = len(count_num_li)
orders_find_sql += """ORDER BY bo.createtime DESC LIMIT %s OFFSET %s; """ % (order_page_size, order_page_offset)
orders_find = await sor.sqlExe(orders_find_sql, {})
return {
'status': True,
'msg': 'get baidu orders success',
'data': {
'pageSize': order_page_size,
'totalCount': count_num,
'pageNo': ns['pageNo'],
'orders': orders_find
}
}
ret = await get_local_baidu_orders(params_kw)
return ret

47
b/baiduc/get_tokenid.dspy Normal file
View File

@ -0,0 +1,47 @@
async def get_tokenid(ns={}):
userid = await get_user()
db = DBPools()
async with db.sqlorContext('kboss') as sor:
baidu_user_id_li = await sor.R('baidu_users', {'user_id': userid, 'del_flg': '0'})
if baidu_user_id_li:
baidu_user_id = baidu_user_id_li[0]['baidu_id']
else:
return {
'status': False,
'msg': '没有找到对应的百度用户'
}
method = "POST"
url = 'https://sts.bj.baidubce.com/v1/signinSecurityToken?userId=%s' % baidu_user_id
x_bce_date = time.gmtime()
x_bce_date = time.strftime('%Y-%m-%dT%H:%M:%SZ', x_bce_date)
header = {
"Host": "sts.bj.baidubce.com",
"Content-Type": "application/json",
'x_bce_date': x_bce_date
}
header2 = x_bce_date
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header) as res:
data_token = await res.json()
if data_token.get('sessionToken'):
return {
'status': True,
'msg': 'get token success',
'data': data_token.get('sessionToken')
}
else:
return {
'status': False,
'msg': 'get token failed, %s' % data_token,
'header': header,
'header2': header2
}
ret = await get_tokenid(params_kw)
return ret

56
b/baiduc/index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<style type="text/css">
body{
font-family: 'Courgette', cursive;
}
body{
background:#f3f3e1;
}
.wrap{
margin:0 auto;
width:1000px;
}
.logo{
margin-top:50px;
}
.logo h1{
font-size:200px;
color:#8F8E8C;
text-align:center;
margin-bottom:1px;
text-shadow:1px 1px 6px #fff;
}
.logo p{
color:rgb(228, 146, 162);
font-size:20px;
margin-top:1px;
text-align:center;
}
.logo p span{
color:lightgreen;
}
.sub a{
color:white;
background:#8F8E8C;
text-decoration:none;
padding:7px 120px;
font-size:13px;
font-family: arial, serif;
font-weight:bold;
-webkit-border-radius:3em;
-moz-border-radius:.1em;
-border-radius:.1em;
}
</style>
<body>
<div class="wrap">
<div class="logo">
<h1>404</h1>
<p>The Page not Found</p>
<div class="sub">
<p><a href="/">Back</a></p>
</div>
</div>
</div>
</body>

View File

@ -0,0 +1,97 @@
async def time_convert(resoucetime=None):
if not resoucetime:
return
utc_time = datetime.datetime.strptime(resoucetime, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=datetime.timezone.utc)
beijing_time = utc_time.astimezone(datetime.timezone(datetime.timedelta(hours=8)))
return beijing_time.strftime("%Y-%m-%d %H:%M:%S")
async def get_order_list_base_page(baidu_id, pageNo=1, pageSize=500):
ns = {'queryAccountId': baidu_id, 'pageNo': pageNo, 'pageSize': pageSize}
method = 'POST'
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/list?%s' % ns_format
header = {
"Host": "billing.baidubce.com",
"ContentType": "application/json;charset=UTF-8"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=ns) as res:
data_orders = await res.json()
return data_orders
async def update_baidu_order_list(ns={}):
"""
ns = {'queryAccountId': '139fc7a23b314596ad78b6bb8e7c1503', 'orderType': 'REFUND'}
:return:
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
username = None
# 更新机构下全部用户订单信息
if ns.get('orgid'):
users_find_sql = """SELECT DISTINCT b.baidu_id FROM organization o INNER JOIN users u ON o.id = u.orgid INNER JOIN baidu_users b ON u.id = b.user_id WHERE o.parentid = '%s' AND b.del_flg = '0';""" % ns.get('orgid')
users = await sor.sqlExe(users_find_sql, {})
# 更新个人订单信息
elif ns.get('userid'):
users = await sor.R('baidu_users', {'user_id': ns['userid']})
username_li = await sor.R('users', {'id': ns['userid']})
username = username_li[0]['username'] if username_li else None
else:
users = []
update_count = 0
add_count = 0
for baidu_id in users:
data_orders = await get_order_list_base_page(baidu_id['baidu_id'], pageNo=1, pageSize=1000)
page_num_count = int(data_orders['totalCount'] / data_orders['pageSize']) + 1
for page_num in range(1, page_num_count + 1):
data_orders = await get_order_list_base_page(baidu_id['baidu_id'], pageNo=page_num, pageSize=1000)
orders = data_orders['orders']
for item in orders:
updatetime = await time_convert(item.get('updateTime')) if item.get('updateTime') else None
ns_dic = {
"id": uuid(),
"orderid": item.get("uuid"),
"ordertype": item.get("type"),
"accountid": item.get("accountId"),
"servicetype": item.get("serviceType"),
"producttype": item.get("productType"),
"shortids": ','.join(item['shortIds']) if item.get('shortIds') else '',
"price": item.get("price"),
"status": item.get("status"),
"autoreneworder": '1' if item.get("autoRenewOrder") else '0',
"createtime": await time_convert(item.get('createTime')) if item.get(
'createTime') else None,
"updatetime": updatetime
}
ns_exist_order = {
'orderid': item.get("uuid")
}
exist_order = await sor.R('baidu_orders', ns_exist_order)
if exist_order and exist_order[0]['updatetime'] != updatetime:
update_refund_sql = """UPDATE baidu_orders SET price = '%s', status = '%s', updatetime = '%s' WHERE orderid = '%s';""" % \
(item.get("price"), item.get("status"), updatetime,
item.get("uuid"))
await sor.sqlExe(update_refund_sql, {})
update_count += 1
if not exist_order:
await sor.C('baidu_orders', ns_dic)
add_count += 1
return {
'status': True,
'msg': '同步数据成功, 新增 %s 条, 更新 %s 条' % (add_count, update_count),
'data': {
'username': username
}
}
ret = await update_baidu_order_list(params_kw)
return ret

View File

@ -0,0 +1,55 @@
async def create_baiduuser(ns):
"""
ns = {
"name": "用户名",
"email": "邮箱",
"mobilePhone": "手机号",
"accountType": "0"为个人|“1”为企业
}
:param ns:
:return:
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
user = await sor.R('users',{'id':ns.get('userid')})
data = {'name':user[0]['username'],'mobilePhone':user[0]['mobile'],'accountType':'0'}
method = "POST"
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://iam.bj.baidubce.com/v1/vs/account?%s' % ns_format
header = {
"Host": "iam.bj.baidubce.com",
"Content-Type": "application/json"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=data) as res:
data_ = await res.json()
if not data_.get('userId'):
return {
'status': False,
'msg': '创建用户失败',
'data': data_
}
else:
#用户创建成功
userdata = {
'id' : uuid(),
# 'id' : UUID(),
'user_id' : ns.get('userid'),
'baidu_id' : data_.get('userId'),
'baidu_username' : data_.get('name'),
}
await sor.C('baidu_users',userdata)
return {
'status': True,
'msg': '创建用户成功',
'data': data_
}
ret = await create_baiduuser(params_kw)
return ret

View File

@ -0,0 +1,33 @@
async def get_baiduQualifyInfo(ns):
"""
获取百度实名认证接口
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
user = await sor.R('baidu_users',{'user_id':ns.get('user_id')})
if len(user) >= 1:
nss = {}
nss['accountId'] = user[0]['baidu_id']
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in nss.items()])
url = 'https://qualify.baidubce.com/v1/getQualifyInfo?%s' % ns_format
method = 'GET'
header = {
"Host": "qualify.baidubce.com",
"ContentType": "application/json;charset=UTF-8"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=ns) as res:
data_ = await res.json()
if data_['qualifyType'] != None and data_['status'] == 'PASS':
return {'status': True, 'msg': '实名认证通过'}
else:
return {'status': False, 'msg': '实名认证未通过'}
else:
return {'status': False, 'msg': '百度用户创建失败'}
ret = await get_baiduQualifyInfo(params_kw)
return ret

View File

@ -0,0 +1,627 @@
async def user_action_record(ns={}):
ns_dic = {
'id': uuid(),
'source': '百度智能云',
'orderid': ns.get('orderid'),
'ordertype': ns.get('ordertype'),
'userid': ns.get('userid'),
'reason': ns.get('reason')
}
db = DBPools()
async with db.sqlorContext('kboss') as sor:
await sor.C('user_action', ns_dic)
async def time_convert(resoucetime=None):
if not resoucetime:
return
utc_time = datetime.datetime.strptime(resoucetime, "%Y-%m-%dT%H:%M:%SZ").replace(tzinfo=datetime.timezone.utc)
beijing_time = utc_time.astimezone(datetime.timezone(datetime.timedelta(hours=8)))
return beijing_time.strftime("%Y-%m-%d %H:%M:%S")
async def cal_expire_time(history_time=None, chargeduration=None, unit=None):
chargeduration = int(chargeduration)
# 当前时间
# now = datetime.datetime.now()
now = datetime.datetime.strptime(history_time, '%Y-%m-%d %H:%M:%S')
if unit == 'MONTH':
expire_time = now + dateutil.relativedelta.relativedelta(months=chargeduration)
elif unit == 'YEAR':
expire_time = now + dateutil.relativedelta.relativedelta(years=chargeduration)
else:
expire_time = None
if expire_time:
return str(expire_time)
else:
return None
async def affirmbz_order(ns={}):
"""确认支付"""
order_type = ns.get('order_type')
sor = ns['sor']
orgid = await sor.R('bz_order', {'id': ns['orderid']})
servicename = orgid[0]['servicename']
# product_url = None
# if ('BCC' in servicename) or ('GPU' in servicename):
# product_url = 'https://console.vcp.baidu.com/bcc/#/bcc/instance/list'
date = await get_business_date(sor=None)
# await sor.U('bz_order',{'id':ns['orderid'],'order_date': date})
count = await getCustomerBalance(sor, orgid[0]['customerid'])
if count == None:
count = 0
if count - float(orgid[0]['amount']) < 0:
pricedifference = count - round(orgid[0]['amount'],2)
return {'status': False, 'msg': '账户余额不足','pricedifference': round(pricedifference,2)}
await order2bill(ns['orderid'], sor)
bills = await sor.R('bill', {'orderid': ns['orderid'], 'del_flg': '0'})
try:
# 需要加事务
for i in bills:
ba = BillAccounting(i)
r = await ba.accounting(sor)
dates = datetime.datetime.now()
await sor.U('bz_order', {'id': ns['orderid'], 'order_status': '1','create_at':dates})
await sor.U('bill', {'id': ns['orderid'], 'bill_state': '1'})
order_goods = await sor.R('order_goods', {'orderid': ns['orderid']})
for j in order_goods:
# 处理退订逻辑
if order_type == 'REFUND':
# 找到资源并更新时间
resource_find_sql = """select id from customer_goods where resourceid = '%s';""" % j['resourceids']
resource_find_li = await sor.sqlExe(resource_find_sql, {})
resource_find_id = resource_find_li[0]['id']
await sor.U('customer_goods', {'id': resource_find_id, 'del_flg': '1'})
# 处理续费逻辑
elif order_type == 'RENEW':
# 找到资源并更新时间
resource_find_sql = """select id from customer_goods where resourceid = '%s' and del_flg = '0';""" % j['resourceids']
resource_find_li = await sor.sqlExe(resource_find_sql, {})
resource_find_id = resource_find_li[0]['id']
await sor.U('customer_goods', {'id': resource_find_id, 'start_date': j['resourcestarttime'], 'expire_date': j['resourceendtime']})
# 处理购买逻辑
else:
product = await sor.R('product', {'id': j['productid']})
nss = {}
nss['id'] = uuid()
# nss['id'] = UUID()
nss['providerrid'] = product[0]['providerid']
nss['productname'] = product[0]['name']
nss['productdesc'] = product[0]['description']
nss['customerid'] = orgid[0]['customerid']
nss['productid'] = product[0]['id']
nss['specdataid'] = j['spec_id']
nss['orderid'] = orgid[0]['id']
nss['start_date'] = j['resourcestarttime']
nss['expire_date'] = j['resourceendtime']
nss['resourceid'] = j['resourceids']
nss['orderkey'] = j['orderkey']
if product_url:
nss['product_url'] = product_url
else:
spec = json.loads(product[0]['spec_note']) if isinstance(product[0]['spec_note'], str) else product[0]['spec_note']
spec_list_url = [item['value'] for item in spec if item['configName'] == 'listUrl']
nss['product_url'] = spec_list_url[0] if spec_list_url else 'https://console.vcp.baidu.com/bcc/#/bcc/instance/list'
await sor.C('customer_goods', nss)
return {'status': True, 'msg': '支付成功'}
except Exception as error:
raise error
async def baidu_new_update_resouce(ns={}):
# 增加延迟
import asyncio
await asyncio.sleep(12)
db = DBPools()
async with db.sqlorContext('kboss') as sor:
baidu_users = await sor.R('baidu_users', {'user_id': ns.get('userid'),'del_flg':'0'})
user = await sor.R('users', {'id': ns.get('userid')})
orgid = await sor.R('organization', {'id': user[0]['orgid']})
nss = {'uuids': [ns.get('order_id')], 'queryAccountId': baidu_users[0]['baidu_id']}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/getByUuid?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com",
"ContentType": "application/json;charset=UTF-8"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=nss) as res:
data_ = await res.json()
with open('baidu_new_order_after_confirm.txt', 'a+') as f:
f.write(json.dumps(data_) + '\n')
orders = data_['orders']
for item in orders:
order_items = item['orderItems']
for order_info in order_items:
resourceids = ','.join(order_info['shortIds']) if order_info.get('shortIds') else ''
if not resourceids:
continue
resourcestarttime = await time_convert(order_info.get('resourceStartTime')) if order_info.get(
'resourceStartTime') else None
resourceendtime = await time_convert(order_info.get('resourceEndTime')) if order_info.get(
'resourceEndTime') else None
order_key = order_info['key']
update_order_goods_sql = """ UPDATE order_goods og
JOIN bz_order o ON og.orderid = o.id
SET
og.resourceids = '%s',
og.resourcestarttime = '%s',
og.resourceendtime = '%s'
WHERE
og.orderkey = '%s'
AND o.provider_orderid = '%s'; """ \
% (resourceids, resourcestarttime, resourceendtime, order_key, ns.get('order_id'))
await sor.sqlExe(update_order_goods_sql, {})
update_customer_goods_sql = """ UPDATE customer_goods og
JOIN bz_order o ON og.orderid = o.id
SET
og.resourceid = '%s',
og.start_date = '%s',
og.expire_date = '%s'
WHERE
og.orderkey = '%s'
AND o.provider_orderid = '%s'; """ \
% (resourceids, resourcestarttime, resourceendtime, order_key, ns.get('order_id'))
await sor.sqlExe(update_customer_goods_sql, {})
async def baidu_order_cancel(ns={}):
baidu_id = ns['baidu_id']
order_id = ns['order_id']
paydata = {'queryAccountId': baidu_id, 'orderIds': [order_id]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
return {
'status': True,
'msg': 'order cancel success'
}
async def get_baidu_orderlist(ns={}):
"""
百度支付
1、获取订单
2、算出购买的产品折扣
3、比对账号余额
"""
# 增加延迟
import asyncio
await asyncio.sleep(2)
db = DBPools()
async with db.sqlorContext('kboss') as sor:
baidu_users = await sor.R('baidu_users', {'user_id': ns.get('userid'),'del_flg':'0'})
user = await sor.R('users', {'id': ns.get('userid')})
orgid = await sor.R('organization', {'id': user[0]['orgid']})
nss = {'uuids': [ns.get('order_id')], 'queryAccountId': baidu_users[0]['baidu_id']}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/getByUuid?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com",
"ContentType": "application/json;charset=UTF-8"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=nss) as res:
data_ = await res.json()
with open('baidu_new_order.txt', 'a+') as f:
f.write(json.dumps(data_) + '\n')
orders = data_['orders']
serviceType = orders[0]['orderItems']
# 可能获取得到的是延迟订单
if orders[0]['type'] == 'REFUND' and orders[0]['status'] != 'CREATED':
return {
'status': False,
'msg': 'delay_order'
}
# 避免重复退订
if orders[0]['type'] == 'REFUND' and orders[0]['status'] == 'CREATED':
order_history = await sor.R('bz_order', {'provider_orderid': ns.get('order_id'), 'business_op': 'BUY_REVERSE', 'order_status': '1'})
if order_history:
print('此订单之前已经退费成功')
return {
'status': True,
'msg': '此订单之前已经退费成功'
}
# 如果是退款 更新数据库状态
if orders[0]['type'] == 'REFUND':
updatetime = await time_convert(orders[0]['updateTime']) if orders[0].get('updateTime') else None
update_refund_sql = """UPDATE baidu_orders SET price = '%s', status = '%s', updatetime = '%s' WHERE orderid = '%s';""" % \
(float(orders[0]['price']), orders[0]['status'], updatetime, ns.get('order_id'))
await sor.sqlExe(update_refund_sql, {})
productType = 'prepay'
# 判断订单item中productType是否有后付费的产品
for item in orders:
order_items = item['orderItems']
for order_info in order_items:
postpay_price = order_info['itemFee']['price'] if order_info.get('itemFee') else order_info['catalogPrice']
if not postpay_price:
# cpt1Price: 固定配置,按分钟计费
postpay_price = order_info['pricingDetail'].get('cpt1Price') if order_info.get('pricingDetail') else 0
# 确定是否是后付费订单
if order_info['productType'] == 'postpay' and postpay_price != 0:
productType = 'postpay'
# 获取余额
user_balance = await getCustomerBalance(sor, orgid[0]['id'])
# 判断余额是否大于50
if user_balance < 50:
await sor.rollback()
paydata = {'queryAccountId': baidu_users[0]['baidu_id'], 'orderIds': [ns.get('order_id')]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '后付费 该账号余额不足50无法完成购买'
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '您的余额小于该产品的起购金额50元, 目前无法购买立即充值'
}
# 实付价格
total_price = 0
# productType = ''
# 买/续/退 字段映射
order_type = orders[0]['type']
if order_type == 'NEW':
business_op = 'BUY'
elif order_type == 'RENEW':
business_op = 'RENEW'
elif order_type == 'REFUND':
business_op = 'BUY_REVERSE'
else:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '支付形式目前仅包含购买,续费,退订'
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '线上暂不支持, 请联系售后'
}
try:
# 生成本地订单
bz_ns = {}
bz_ns['id'] = uuid()
bz_ns['order_status'] = '0'
bz_ns['business_op'] = business_op
bz_ns['userid'] = ns.get('userid')
bz_ns['customerid'] = orgid[0]['id']
bz_ns['order_date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
bz_ns['thirdparty_order'] = ns.get('order_id')
bz_ns['source'] = '百度智能云'
# bz_ns['originalprice'] = orders[0]['price']
bz_ns['originalprice'] = sum(i['catalogPrice'] for i in serviceType)
bz_ns['provider_orderid'] = ns.get('order_id')
bz_ns['ordertype'] = orders[0]['productType']
bz_ns['servicename'] = orders[0]['serviceType']
bz_ns['autoreneworder'] = '1' if orders[0]['autoRenewOrder'] else '0'
if ns.get('specdataid'):
bz_ns['specdataid'] = ns['specdataid']
await sor.C('bz_order', bz_ns)
for i in serviceType:
# if i['productType'] == 'prepay':
# # 预付费
# productType = 'prepay'
# financePrice = 0
# 获取产品id
product = await sor.R('product', {'providerpid': 'baidu_' + i['serviceType'], 'del_flg': '0'})
if not product:
return {
'status': False,
'msg': '未配置该产品, 请联系售后处理'
}
# 获取协议
saleprotocol_to_person = await sor.R('saleprotocol',
{'bid_orgid': orgid[0]['id'], 'offer_orgid': orgid[0]['parentid'],
'del_flg': '0'})
# 等于空就代表这个客户没有特殊折扣,就要找到买方为*的协议
saleprotocol_to_all = await sor.R('saleprotocol', {'bid_orgid': '*', 'offer_orgid': orgid[0]['parentid'],
'del_flg': '0', 'salemode': '0'})
if saleprotocol_to_person:
product_salemode = await sor.R('product_salemode',
{'protocolid': saleprotocol_to_person[0]['id'],
'productid': product[0]['id'],
'del_flg': '0'})
if not product_salemode:
product_salemode = await sor.R('product_salemode',
{'protocolid': saleprotocol_to_all[0]['id'],
'productid': product[0]['id'],
'del_flg': '0'})
else:
product_salemode = await sor.R('product_salemode',
{'protocolid': saleprotocol_to_all[0]['id'],
'productid': product[0]['id'],
'del_flg': '0'})
if not product_salemode:
return {
'status': False,
'msg': '还未上线这个产品的协议配置'
}
supply_price = i['itemFee']['price'] if i.get('itemFee') else i['catalogPrice']
financePrice = abs(supply_price * product_salemode[0]['discount'])
total_price += financePrice
# 添加订单子表
nss = {}
nss['id'] = uuid()
nss['orderid'] = bz_ns['id']
nss['productid'] = product[0]['id']
nss['providerid'] = product[0]['providerid']
if i['count'] > 1:
nss['list_price'] = abs(i['realCatalogPrice'] / i['count'])
else:
nss['list_price'] = abs(i['realCatalogPrice'])
nss['discount'] = product_salemode[0]['discount']
nss['quantity'] = i['count']
nss['price'] = abs(round(nss['list_price'] * product_salemode[0]['discount'], 2))
# 计算总价
# nss['amount'] = round(total_price, 2)
nss['amount'] = abs(round(nss['price'] * nss['quantity'], 2))
nss['chargemode'] = i.get('productType')
nss['servicename'] = i.get('serviceType')
nss['chargeduration'] = i.get('time')
nss['unit'] = i.get('timeUnit')
nss['resourceids'] = ','.join(i['shortIds']) if i.get('shortIds') else ''
nss['orderkey'] = i.get('key')
# 如果是续费订单 由于没有返回日期, 重新计算日期
if order_type == 'RENEW':
history_time_sql = "select resourcestarttime, resourceendtime from order_goods where resourceids = '%s' order by resourceendtime desc;" % \
nss['resourceids']
history_time = await sor.sqlExe(history_time_sql, {})
new_end_time = await cal_expire_time(history_time=history_time[0]['resourceendtime'],
chargeduration=nss['chargeduration'], unit=nss['unit'])
# 开始日期不变 更新到期日期
nss['resourcestarttime'] = history_time[0]['resourcestarttime']
nss['resourceendtime'] = new_end_time
else:
if i.get('resourceStartTime'):
nss['resourcestarttime'] = await time_convert(i.get('resourceStartTime'))
else:
nss['resourcestarttime'] = await time_convert(orders[0]['updateTime'])
if i.get('resourceEndTime'):
nss['resourceendtime'] = await time_convert(i.get('resourceEndTime'))
# 后付费没有资源结束时间
if i.get('productType') == 'prepay':
end_time = await time_convert(orders[0]['updateTime'])
nss['resourceendtime'] = await cal_expire_time(history_time=end_time,
chargeduration=nss['chargeduration'],
unit=nss['unit'])
else:
nss['resourceendtime'] = None
await sor.C('order_goods', nss)
# 循环后更新订单中总价
await sor.U('bz_order', {'id': bz_ns['id'], 'amount': round(total_price, 2)})
except Exception as e:
await baidu_order_cancel({'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')})
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '发生错误, %s' % str(e)[:100]
}
await user_action_record(ns_record)
import traceback
with open('baiducloud_err.txt', 'w') as f:
f.write(str(e)+ traceback.format_exc())
traceback.print_exc()
await sor.rollback()
return {
'status': False,
'msg': '产品错误, 请联系售后'
}
# 判断用户账户余额是否足够支付
try:
count = await getCustomerBalance(sor, orgid[0]['id'])
if order_type == 'REFUND':
count = total_price + 0.1
if round(total_price,2) <= count:
#判断预付费或者后付费
if productType == 'prepay' or productType == 'postpay':
# 调用扣费接口
affirmbz_order_ns = {
'sor': sor,
'orderid': bz_ns['id'],
'order_type': order_type
}
affirmbz_order_res = await affirmbz_order(affirmbz_order_ns)
if not affirmbz_order_res['status']:
# if True:
await sor.rollback()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '支付错误, 请联系售后'
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '支付错误, 请联系售后'
}
# 预配置local_refund用于本地操作
if order_type == 'REFUND' and not ns.get('local_refund'):
return {
'status': True,
'msg': '本地退费成功'
}
else:
# 调用支付订单接口
paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderId':ns.get('order_id')}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/pay?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
data_ = await res.json()
if data_ == {'success': True}:
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '购买成功'
}
await user_action_record(ns_record)
ns_cron_job = {
'id': uuid(),
'source': 'baidu',
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': 'buy success'
}
await sor.C('baidu_cron_job', ns_cron_job)
# return {
# 'status': True,
# 'orderid': bz_ns['id']
# }
else:
await sor.rollback()
await baidu_order_cancel(
{'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')})
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '支付成功后, order_pay接口错误, 回滚, %s' % str(data_)[:400]
}
await user_action_record(ns_record)
return {
'status': False,
'msg': '产品分配排队中, 请联系售后详询'
}
else:
# 取消订单
await sor.rollback()
paydata = {'queryAccountId': baidu_users[0]['baidu_id'], 'orderIds': [ns.get('order_id')]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '无法购买后付费产品'
}
await user_action_record(ns_record)
return {'status': False, 'msg': '无法购买后付费产品'}
else:
#取消订单
await sor.rollback()
paydata = {'queryAccountId':baidu_users[0]['baidu_id'],'orderIds':[ns.get('order_id')]}
ns_format = '&'.join(['%s=%s' % (k, v) for k, v in ns.items()])
url = 'https://billing.baidubce.com/v1/order/cancel?%s' % ns_format
method = 'POST'
header = {
"Host": "billing.baidubce.com"
}
header = await get_auth_header(method=method, url=url, header=header)
async with aiohttp_client.request(
method=method,
url=url,
headers=header,
json=paydata) as res:
await res.json()
ns_record = {
'orderid': ns.get('order_id'),
'ordertype': orders[0]['type'],
'userid': ns.get('userid'),
'reason': '该账号余额不足,无法完成购买'
}
await user_action_record(ns_record)
return {'status': False,'msg': '该账号余额不足,无法完成购买'}
except Exception as e:
await baidu_order_cancel({'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')})
import traceback
with open('baiducloud_err.txt', 'w') as f:
f.write(str(e)+ traceback.format_exc())
traceback.print_exc()
await sor.rollback()
return {
'status': False,
'msg': '产品错误, 请联系售后'
}
# 更新资源时间 资源id
# if order_type == 'NEW':
# await baidu_new_update_resouce(ns)
return {
'status': True,
'orderid': bz_ns['id'],
'originalprice': bz_ns.get('originalprice'),
'servicename': bz_ns.get('servicename'),
'amount': total_price
}
ret = await get_baidu_orderlist(params_kw)
return ret

56
b/baiducloud/index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<style type="text/css">
body{
font-family: 'Courgette', cursive;
}
body{
background:#f3f3e1;
}
.wrap{
margin:0 auto;
width:1000px;
}
.logo{
margin-top:50px;
}
.logo h1{
font-size:200px;
color:#8F8E8C;
text-align:center;
margin-bottom:1px;
text-shadow:1px 1px 6px #fff;
}
.logo p{
color:rgb(228, 146, 162);
font-size:20px;
margin-top:1px;
text-align:center;
}
.logo p span{
color:lightgreen;
}
.sub a{
color:white;
background:#8F8E8C;
text-decoration:none;
padding:7px 120px;
font-size:13px;
font-family: arial, serif;
font-weight:bold;
-webkit-border-radius:3em;
-moz-border-radius:.1em;
-border-radius:.1em;
}
</style>
<body>
<div class="wrap">
<div class="logo">
<h1>404</h1>
<p>The Page not Found</p>
<div class="sub">
<p><a href="/">Back</a></p>
</div>
</div>
</div>
</body>

13
b/bill/addbill.dspy Normal file
View File

@ -0,0 +1,13 @@
async def addbill(ns):
"""添加账单"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
ns['id'] = uuid()
await sor.C('bill', ns)
return {'status': True, 'msg': '添加成功'}
return {'status': False, 'msg': '添加失败'}
ret = await addbill(params_kw)
return ret

12
b/bill/dlebill.dspy Normal file
View File

@ -0,0 +1,12 @@
async def dlebill(ns):
"""删除账单"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
ns['del_flg'] = '1'
await sor.U('bill', ns)
return {'status': True, 'msg': '删除成功'}
return {'status': False, 'msg': '删除失败'}
ret = await dlebill(params_kw)
return ret

17
b/bill/getbill.dspy Normal file
View File

@ -0,0 +1,17 @@
async def getbill(ns):
"""查询账单"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
ns['del_flg'] = '0'
ns['sort'] = 'create_at'
ns['order'] = 'desc'
reacs = await sor.R('bill',ns)
for i in reacs['rows']:
ns = {'id':i['customerid'],'del_fig':'0'}
customer = await sor.R('organization', ns)
i['orgname'] = customer[0]['orgname']
return {'status': True, 'data': reacs}
ret = await getbill(params_kw)
return ret

56
b/bill/index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<style type="text/css">
body{
font-family: 'Courgette', cursive;
}
body{
background:#f3f3e1;
}
.wrap{
margin:0 auto;
width:1000px;
}
.logo{
margin-top:50px;
}
.logo h1{
font-size:200px;
color:#8F8E8C;
text-align:center;
margin-bottom:1px;
text-shadow:1px 1px 6px #fff;
}
.logo p{
color:rgb(228, 146, 162);
font-size:20px;
margin-top:1px;
text-align:center;
}
.logo p span{
color:lightgreen;
}
.sub a{
color:white;
background:#8F8E8C;
text-decoration:none;
padding:7px 120px;
font-size:13px;
font-family: arial, serif;
font-weight:bold;
-webkit-border-radius:3em;
-moz-border-radius:.1em;
-border-radius:.1em;
}
</style>
<body>
<div class="wrap">
<div class="logo">
<h1>404</h1>
<p>The Page not Found</p>
<div class="sub">
<p><a href="/">Back</a></p>
</div>
</div>
</div>
</body>

11
b/bill/upbill.dspy Normal file
View File

@ -0,0 +1,11 @@
async def upbill(ns):
"""修改账单"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
await sor.U('bill', ns)
return {'status': True, 'msg': '修改成功'}
return {'status': False, 'msg': '修改失败'}
ret = await upbill(params_kw)
return ret

56
b/bo_old/addbz_order.dspy Normal file
View File

@ -0,0 +1,56 @@
async def addbz_order(ns):
"""
生成订单 立即下单
userid : 用户id
`goods`'产品id',
`spec_id` '规格id',
`quantity`'数量',
`transname` '交易名称',
`providerid` '供应商id',
`order_status` '0:未支付1:已交付2:已关闭3:已取消4:后付费',
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
try:
user = await sor.R('users', {'id': await get_user()})
orgid = await sor.R('organization', {'id': user[0]['orgid']})
amountadll = 0
bz_ns = {}
# bz_ns['id'] = UUID()
bz_ns['id'] = uuid()
bz_ns['order_status'] = '0'
bz_ns['business_op'] = 'BUY'
bz_ns['userid'] = await get_user()
bz_ns['customerid'] = orgid[0]['id']
bz_ns['order_date'] = datetime.datetime.now().strftime("%Y-%m-%d")
if ns.get('specdataid'):
bz_ns['specdataid'] = ns['specdataid']
await sor.C('bz_order', bz_ns)
# 添加账户表
nss = {}
nss['id'] = uuid()
# nss['id'] = UUID()
nss['orderid'] = bz_ns['id']
nss['productid'] = ns.get('productid')
nss['providerid'] = ns.get('providerid')
nss['list_price'] = ns.get('list_price')
nss['discount'] = ns.get('discount')
nss['quantity'] = ns.get('quantity')
nss['price'] = ns.get('amount')
nss['spec_id'] = ns.get('spec_id')
if int(ns.get('quantity')) > 1:
nss['amount'] = float(ns['amount']) * int(ns['quantity'])
amountadll += nss['amount']
else:
nss['amount'] = ns['amount']
amountadll += float(nss['amount'])
await sor.C('order_goods', nss)
await sor.U('bz_order', {'id': bz_ns['id'], 'amount': amountadll})
return {'status': True, 'msg': '添加成功', 'bz_id': bz_ns['id']}
except Exception as error:
raise error
return {'status': False, 'msg': '添加失败'}
ret = await addbz_order(params_kw)
return ret

View File

@ -0,0 +1,93 @@
async def affirmbz_order(ns):
"""确认支付"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
# 查询产品说明是否是product_sync
order_productid_providerid = await sor.R('order_goods', {'orderid': ns['orderid']})
order_productid = order_productid_providerid[0]['productid']
order_providerid = order_productid_providerid[0]['providerid']
description = (await sor.R('product', {'id': order_productid}))[0]['description']
if description == 'product_sync':
# 根据orderid在order_goods里查询对应账单
# order_providerid = (await sor.R('order_goods', {'orderid': ns['orderid']}))[0]['providerid']
# 查询阿里云得id
ali_id_li = await sor.R('organization', {'orgname': '阿里云'})
if ali_id_li:
ali_id = ali_id_li[0]['id']
else:
ali_id = None
# 查询开元云得id
k_id_li = await sor.R('organization', {'orgname': '开元云'})
if k_id_li:
k_id = k_id_li[0]['id']
else:
k_id = None
target_id = None
if order_providerid == ali_id:
target_id = ali_id
if order_providerid == k_id:
target_id = k_id
if target_id:
# 查询业主机构针对所有客户的普通协议
protocolid = (await sor.R('saleprotocol', {'offer_orgid': 'mIWUHBeeDM8mwAFPIQ8pS', 'bid_orgid': '*', 'salemode': '2', 'del_flg': '0'}))[0]['id']
# 在产品价格表中更新价格配置
id_sql = """select id, price from product_salemode where protocolid = '%s' and providerid = '%s' and productid = '%s' order by price desc limit 1;""" % (protocolid, target_id, order_productid)
id_find = (await sor.sqlExe(id_sql, {}))[0]['id']
# 查询价格
current_price = (await sor.R('bz_order', {'id': ns['orderid']}))[0]['amount']
await sor.U('product_salemode', {'id': id_find, 'price': current_price})
orgid = await sor.R('bz_order', {'id': ns['orderid']})
date = await get_business_date(sor=None)
await sor.U('bz_order',{'id':ns['orderid'],'order_date': date})
count = await getCustomerBalance(sor, orgid[0]['customerid'])
if count == None:
count = 0
if count - float(orgid[0]['amount']) < 0:
pricedifference = count - round(orgid[0]['amount'],2)
return {'status': False, 'msg': '账户余额不足','pricedifference': round(pricedifference,2)}
await order2bill(ns['orderid'], sor)
bills = await sor.R('bill', {'orderid': ns['orderid'], 'del_flg': '0'})
try:
# 需要加事务
for i in bills:
ba = BillAccounting(i)
r = await ba.accounting(sor)
dates = datetime.datetime.now()
await sor.U('bz_order', {'id': ns['orderid'], 'order_status': '1','create_at':dates})
await sor.U('bill', {'id': ns['orderid'], 'bill_state': '1'})
order_goods = await sor.R('order_goods', {'orderid': ns['orderid']})
for j in order_goods:
product = await sor.R('product', {'id': j['productid']})
nss = {}
nss['id'] = uuid()
# nss['id'] = UUID()
nss['providerrid'] = product[0]['providerid']
nss['productname'] = product[0]['name']
nss['productdesc'] = product[0]['description']
nss['customerid'] = orgid[0]['customerid']
nss['productid'] = product[0]['id']
nss['specdataid'] = j['spec_id']
nss['orderid'] = orgid[0]['id']
nss['start_date'] = datetime.datetime.now().strftime("%Y-%m-%d")
if ns.get('product_url'):
nss['product_url'] = ns.get('product_url')
await sor.C('customer_goods', nss)
v = {}
v['orderid'] = orgid[0]['id']
v['customerid'] = orgid[0]['customerid']
v['providerid'] = product[0]['providerid']
v['productid'] = product[0]['id']
v['quantity'] = j['quantity']
await path_call('../pub/hpc_save_bill.dspy', v)
return {'status': True, 'msg': '支付成功'}
except Exception as error:
raise error
else:
return {'status': False, 'msg': '参数错误'}
return {'status': False, 'msg': '支付失败'}
ret = await affirmbz_order(params_kw)
return ret

View File

@ -0,0 +1,18 @@
async def cancelbz_order(ns):
"""取消订单"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
try:
# 需要加事务
await sor.U('bz_order', {'id': ns['orderid'], 'order_status': '3'})
return {'status': True, 'msg': '取消订单'}
except Exception as error:
raise error
else:
return {'status': False, 'msg': '参数错误'}
return {'status': False, 'msg': '取消失败'}
ret = await cancelbz_order(params_kw)
return ret

24
b/bo_old/chargeback.dspy Normal file
View File

@ -0,0 +1,24 @@
async def chargeback(ns):
""" 退单
id:订单的id
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
await sor.U('bz_order', {'id':ns['id'],'business_op':'BUY_REVERSE','order_status':'0'})
await order2bill(ns['id'], sor)
bills = await sor.R('bill', {'orderid':ns.get('id')})
for i in bills:
ba = BillAccounting(i)
r = await ba.accounting(sor)
order_goods = await sor.R('customer_goods', {'orderid': ns['id']})
for j in order_goods:
await sor.U('customer_goods', {'id': j['id'],'del_flg':'1'})
await sor.U('bz_order', {'id': ns['id'], 'order_status':'3'})
return {'status': True, 'msg': '成功'}
except Exception as e:
raise e
return {'status': False, 'msg': '失败'}
ret = await chargeback(params_kw)
return ret

View File

@ -0,0 +1,51 @@
async def customer_cartpay(ns):
""" 购物车下单
"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
try:
customer_cart = await sor.R('customer_cart', {'id':ns['id']})
amount = 0
count = 0
bz_ns = {}
# bz_ns['id'] = UUID()
bz_ns['id'] = uuid()
for i in eval(ns.get('goods')):
count += 1
cart_goods = await sor.R('cart_goods', {'id': i})
amount += float(cart_goods[0]['amount'])
nss = {}
nss['id'] = uuid()
# nss['id'] = UUID()
nss['orderid'] = bz_ns['id']
nss['productid'] = cart_goods[0]['productid']
product = await sor.R('product', {'id': cart_goods[0]['productid']})
nss['providerid'] = product[0]['providerid']
nss['list_price'] = cart_goods[0].get('list_price')
nss['discount'] = cart_goods[0].get('discount')
nss['quantity'] = cart_goods[0].get('quantity')
nss['price'] = cart_goods[0].get('price')
nss['spec_id'] = cart_goods[0].get('spec_id')
nss['amount'] = cart_goods[0].get('amount')
await sor.C('order_goods', nss)
sql = """ UPDATE cart_goods SET del_flg = '1' WHERE id = ${id}$ """
nsa = {'id': i}
await sor.sqlExe(sql, nsa)
bz_ns['order_status'] = '0'
bz_ns['business_op'] = 'BUY'
bz_ns['amount'] = amount
bz_ns['customerid'] = customer_cart[0]['customerid']
bz_ns['order_date'] = datetime.datetime.now().strftime("%Y-%m-%d")
await sor.C('bz_order', bz_ns)
olen = customer_cart[0]['goods_cnt']
ncount = olen - count
oamount = float(customer_cart[0]['amount'])
namount = oamount - amount
await sor.U('customer_cart', {'id': ns['id'],'amount':namount,'goods_cnt':ncount})
return {'status': True, 'msg': '添加成功', 'bz_id': bz_ns['id']}
except Exception as e:
raise e
return {'status': False, 'msg': '添加失败'}
ret = await customer_cartpay(params_kw)
return ret

12
b/bo_old/dlebz_order.dspy Normal file
View File

@ -0,0 +1,12 @@
async def dlebz_order(ns):
"""删除订单"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
ns['del_flg'] = '1'
await sor.U('bz_order', ns)
return {'status': True, 'msg': '删除成功'}
return {'status': False, 'msg': '删除失败'}
ret = await dlebz_order(params_kw)
return ret

93
b/bo_old/getbz_order.dspy Normal file
View File

@ -0,0 +1,93 @@
async def getbz_order(ns):
"""查询订单详情/我的所有订单"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
try:
ns['del_flg'] = '0'
ns['sort'] = 'create_at desc'
if ns.get('id') and not ns.get('type'):
# 查询订单详情
reacs = await sor.R('bz_order', ns)
reacsgoods = await sor.R('order_goods', {'orderid': ns['id'], 'del_flg': '0'})
for i in reacsgoods:
if i['discount'] == None or i['discount'] == 1.0:
del i['discount']
goods = await sor.R('product', {'id': i['productid'], 'del_flg': '0'})
if len(goods) >= 1:
i['productid'] = goods[0]['name']
i['ptype'] = goods[0]['ptype']
reacs[0]['order_goods'] = reacsgoods
return {'status': True, 'data': reacs}
elif ns.get('type') == '200':
#筛选支付类型
user = await sor.R('users', {'id': await get_user(), 'del_flg': '0'})
orgid = await sor.R('organization', {'id': user[0]['orgid'], 'del_flg': '0'})
ns['customerid'] = orgid[0]['id']
if ns.get('id'):
#根据订单号搜索
reacs = await sor.R('bz_order', {'id': ns['id']})
elif ns.get('start_time'):
sql = """select * from bz_order where del_flg = 0 AND customerid = ${customerid}$ AND order_date >= ${start_time}$ AND order_date <= ${end_time}$ ORDER BY order_date DESC """
start_time = ns.get('start_time') + ' 00:00:00'
end_time = ns.get('end_time') + ' 23:59:59'
reacs = await sor.sqlExe(sql, {'start_time': start_time,'end_time': end_time,'customerid' :ns['customerid']})
else:
reacs = await sor.R('bz_order', {'customerid':ns['customerid'],'sort':'order_date desc','order_status':ns.get('order_status'),'del_flg':'0'})
all_price = 0
if len(reacs) >= 1:
for j in reacs:
reacsgoods = await sor.R('order_goods', {'orderid': j['id'], 'del_flg': '0'})
countlist_price = 0
for i in reacsgoods:
if i['discount'] == None or i['discount'] == 1.0:
del i['discount']
goods = await sor.R('product', {'id': i['productid'], 'del_flg': '0'})
if len(goods) >= 1:
i['productid'] = goods[0]['name']
j['order_goods'] = reacsgoods
countlist_price += i['list_price']
countlist_price *= i['quantity']
if j['order_status'] == '1':
all_price += countlist_price
j['countprice'] = round(countlist_price,2)
if j['countprice'] == 0:
j['countprice'] = j['originalprice']
return {'status': True, 'data': reacs, 'all_price': round(all_price, 2)}
else:
# 我的所有订单
ns['del_flg'] = '0'
ns['sort'] = 'create_at desc'
user = await sor.R('users', {'id': await get_user(), 'del_flg': '0'})
orgid = await sor.R('organization', {'id': user[0]['orgid'], 'del_flg': '0'})
ns['customerid'] = orgid[0]['id']
reacs = await sor.R('bz_order', {'customerid':ns['customerid'],'sort':'create_at desc','del_flg':'0'})
all_price = 0
for j in reacs:
reacsgoods = await sor.R('order_goods', {'orderid': j['id'], 'del_flg': '0'})
countlist_price = 0
for i in reacsgoods:
if i['discount'] == None or i['discount'] == 1.0:
del i['discount']
goods = await sor.R('product', {'id': i['productid'], 'del_flg': '0'})
if len(goods) < 1:
continue
i['ptype'] = goods[0]['ptype']
if len(goods) >= 1:
i['productid'] = goods[0]['name']
j['order_goods'] = reacsgoods
countlist_price += i['list_price']
countlist_price *= i['quantity']
if j['order_status'] == '1':
all_price += countlist_price
j['countprice'] = round(countlist_price,2)
if j['countprice'] == 0:
j['countprice'] = j['originalprice']
return {'status': True, 'data': reacs,'all_price': round(all_price,2)}
except Exception as e:
raise e
return {'status': False, 'msg': '信息错误'}
ret = await getbz_order(params_kw)
return ret

56
b/bo_old/index.html Normal file
View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<style type="text/css">
body{
font-family: 'Courgette', cursive;
}
body{
background:#f3f3e1;
}
.wrap{
margin:0 auto;
width:1000px;
}
.logo{
margin-top:50px;
}
.logo h1{
font-size:200px;
color:#8F8E8C;
text-align:center;
margin-bottom:1px;
text-shadow:1px 1px 6px #fff;
}
.logo p{
color:rgb(228, 146, 162);
font-size:20px;
margin-top:1px;
text-align:center;
}
.logo p span{
color:lightgreen;
}
.sub a{
color:white;
background:#8F8E8C;
text-decoration:none;
padding:7px 120px;
font-size:13px;
font-family: arial, serif;
font-weight:bold;
-webkit-border-radius:3em;
-moz-border-radius:.1em;
-border-radius:.1em;
}
</style>
<body>
<div class="wrap">
<div class="logo">
<h1>404</h1>
<p>The Page not Found</p>
<div class="sub">
<p><a href="/">Back</a></p>
</div>
</div>
</div>
</body>

11
b/bo_old/upbz_order.dspy Normal file
View File

@ -0,0 +1,11 @@
async def upbz_order(ns):
"""修改订单"""
db = DBPools()
async with db.sqlorContext('kboss') as sor:
if ns:
await sor.U('bz_order', ns)
return {'status': True, 'msg': '修改成功'}
return {'status': False, 'msg': '修改失败'}
ret = await upbz_order(params_kw)
return ret

4536
b/bricks/bricks.js Normal file

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More