init project
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
.idea/
|
||||
.DS_Store
|
||||
*.tar
|
||||
*.tar.gz
|
||||
*.rar
|
||||
__pycache__/
|
||||
81
DevOps/deploy_to_server.py
Normal 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
@ -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))
|
||||
BIN
DevOps/kboss生产环境恢复.docx
Normal file
7
DevOps/m.files.sh
Normal 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
@ -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
@ -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
@ -0,0 +1 @@
|
||||
2021004106675236
|
||||
1
alipay/dev/huidiao.txt
Normal file
@ -0,0 +1 @@
|
||||
https://www.kaiyuancloud.cn/dev/pay/payhuidiao.dspy
|
||||
3
alipay/dev/private.txt
Normal 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
@ -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
@ -0,0 +1 @@
|
||||
2021004120652840
|
||||
1
alipay/prod/huidiao.txt
Normal file
@ -0,0 +1 @@
|
||||
https://www.opencomputing.cn/pay/payhuidiao.dspy
|
||||
3
alipay/prod/private.txt
Normal 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
@ -0,0 +1,3 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgD4YlfnWKd4vEHsim6vxLwustbnBBh9IUJwF5rGJ3b7wjYyzMnQZ36Cgf81A685IQ+Ni9GogNDaUWZx9V+qGxZRwaLbktSLnUNwPMudKlUoPyQtqyygU+Bmwg1B+UBzZsz8eG72qOuvu9xNbT72QZqFxzLlo0vzWldijnaPcqukUhTaeIYe1AObI9v3ySAa72GkGCHaSkQqvBLydCJt2mu3zJYhPMKre1oNmQkGYUxLKCwonbABaugOEl7t1vL8mAMlwFg2ihJbYiogGfr2Imt/Y1jy8rftiW41opX1UQ30rgfRYeuEsKvVwuoyqffGHeBSjs53xZkYStYKj0m+8AQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
1
alipay/requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
qrcode
|
||||
1
alipay/test/appid.txt
Normal file
@ -0,0 +1 @@
|
||||
2021004117685170
|
||||
1
alipay/test/huidiao.txt
Normal file
@ -0,0 +1 @@
|
||||
https://www.kaiyuancloud.cn/test/pay/payhuidiao.dspy
|
||||
3
alipay/test/private.txt
Normal 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
@ -0,0 +1,3 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgD4YlfnWKd4vEHsim6vxLwustbnBBh9IUJwF5rGJ3b7wjYyzMnQZ36Cgf81A685IQ+Ni9GogNDaUWZx9V+qGxZRwaLbktSLnUNwPMudKlUoPyQtqyygU+Bmwg1B+UBzZsz8eG72qOuvu9xNbT72QZqFxzLlo0vzWldijnaPcqukUhTaeIYe1AObI9v3ySAa72GkGCHaSkQqvBLydCJt2mu3zJYhPMKre1oNmQkGYUxLKCwonbABaugOEl7t1vL8mAMlwFg2ihJbYiogGfr2Imt/Y1jy8rftiW41opX1UQ30rgfRYeuEsKvVwuoyqffGHeBSjs53xZkYStYKj0m+8AQIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
56
b/Endofday/index.html
Normal 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>
|
||||
|
||||
32
b/Endofday/supplier_accounts.dspy
Normal 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
|
||||
25
b/Organization/addOrganization.dspy
Normal 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
|
||||
38
b/Organization/delOrganization.dspy
Normal 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
|
||||
55
b/Organization/getOrganization.dspy
Normal 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
@ -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>
|
||||
|
||||
22
b/Organization/myOrganization.dspy
Normal 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
|
||||
12
b/Organization/upOrganization.dspy
Normal 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
@ -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
31
b/account/addledgers.dspy
Normal 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
|
||||
122
b/account/email_info.dspy
Normal file
@ -0,0 +1,122 @@
|
||||
# 输入邮件地址,口令和 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_sql = """SELECT * FROM mail_code WHERE LOCATE(mailcode, '%s') > 0 and del_flg = '0';""" % name
|
||||
mail_code = await sor.sqlExe(mail_code_sql, {})
|
||||
# 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
|
||||
35
b/account/getrechargelog.dspy
Normal 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
@ -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>
|
||||
|
||||
9
b/account/open_provider_acc.dspy
Normal 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
@ -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
|
||||
64
b/account/settle_accounts.dspy
Normal 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
@ -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
@ -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
|
||||
54
b/appcode/appCodesAdd.dspy
Normal 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
|
||||
48
b/appcode/appCodesDelete.dspy
Normal 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
|
||||
43
b/appcode/appCodesKvSearch.dspy
Normal 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
|
||||
66
b/appcode/appCodesSearch.dspy
Normal 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
|
||||
46
b/appcode/appCodesUpdate.dspy
Normal 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
@ -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
@ -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>
|
||||
|
||||
291
b/appcode/编码表接口说明.md
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
123
b/appcode/编码表接口说明.txt
Normal 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
@ -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
@ -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
@ -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
|
||||
21
b/apv/delete_apv_business.dspy
Normal 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
|
||||
21
b/apv/delete_apv_template.dspy
Normal 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
|
||||
14
b/apv/get_apv_business.dspy
Normal 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
@ -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
@ -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
@ -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
@ -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
|
||||
17
b/apv/get_apv_template.dspy
Normal 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
@ -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
@ -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
@ -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
|
||||
46
b/apv/send_key_create.dspy
Normal 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
|
||||
21
b/apv/send_key_select.dspy
Normal 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
|
||||
13
b/bill/addbill.dspy
Normal 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
@ -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
@ -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
@ -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
@ -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
|
||||
4536
b/bricks/bricks.js
Normal file
1
b/bricks/bricks.min.js
vendored
Normal file
237
b/bricks/css/bricks.css
Normal file
@ -0,0 +1,237 @@
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.griddata {
|
||||
display: grid;
|
||||
grid-gap: 1px;
|
||||
}
|
||||
|
||||
.modal {
|
||||
padding: 10px;
|
||||
color: #e8e8e8;
|
||||
background-color: rgba(0.3, 0.3, 0.3, 1);
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.modal>.title {
|
||||
background-color: #a0a0a0;
|
||||
}
|
||||
|
||||
.message {
|
||||
padding: 10px;
|
||||
width: 30%;
|
||||
height: 30%;
|
||||
background-color: #f0f0f0;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.error {
|
||||
padding: 10px;
|
||||
width: 30%;
|
||||
height: 30%;
|
||||
background-color: #f0f0f0;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.message>.title {
|
||||
background-color: #3030f0;
|
||||
}
|
||||
|
||||
.vscroll {
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
||||
.hscroll {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.scroll {
|
||||
overflow:scroll;
|
||||
}
|
||||
|
||||
.error>.title {
|
||||
background-color: #f03030;
|
||||
}
|
||||
|
||||
.vbox {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.hbox {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.fixitem {
|
||||
flex:none;
|
||||
}
|
||||
.filler, .hfiller, .vfiller {
|
||||
flex: auto;
|
||||
scroll:auto;
|
||||
}
|
||||
|
||||
.vfiller .vbox:last-child {
|
||||
overflow-x: overlay;
|
||||
}
|
||||
|
||||
.vline {
|
||||
height:1px;
|
||||
background-colir:#999;
|
||||
}
|
||||
|
||||
.hline {
|
||||
height:1px;
|
||||
background-colir:#999;
|
||||
}
|
||||
.hfiller::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.flc {
|
||||
width: 203px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: visible;
|
||||
}
|
||||
|
||||
.vtoolbar {
|
||||
heigth: 100%;
|
||||
background-color: #f1f1f1;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: #d4d4d4;
|
||||
}
|
||||
|
||||
.htoolbar {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
background-color: #f1f1f1;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
.toolbar-button {
|
||||
background-color: inherit;
|
||||
float: left;
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
padding: 14px 16px;
|
||||
transition: 0.3s;
|
||||
border: 1px solid #888;
|
||||
}
|
||||
|
||||
.toolbar-button-active {
|
||||
background-color: #ddd;
|
||||
}
|
||||
|
||||
.tabpanel {
|
||||
background-color: #ededed;
|
||||
border: 3px solid #888;
|
||||
}
|
||||
|
||||
.tabpanel-content {
|
||||
background-color: #f8f8f8;
|
||||
border: 2px solid #888;
|
||||
}
|
||||
|
||||
.multicolumns {
|
||||
column-width: 340px;
|
||||
colomn-gap: 10px'
|
||||
|
||||
}
|
||||
|
||||
.popup {
|
||||
z-index: 1000;
|
||||
position: absolution;
|
||||
background-color: #f1f1f1;
|
||||
border: 1px solid #c1c1c1;
|
||||
}
|
||||
|
||||
.inputbox {
|
||||
background-color: #cccccc;
|
||||
border: 1px solid #bbbbbb;
|
||||
padding: 10px;
|
||||
margin: 0 0 1em 0;
|
||||
}
|
||||
|
||||
button[tooltip]:hover::after {
|
||||
content: attr(tooltip);
|
||||
display: block;
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
div[tooltip]:hover::after {
|
||||
content: attr(tooltip);
|
||||
display: block;
|
||||
position: absolute;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
input[tooltip],
|
||||
div[tooltip] {
|
||||
width: max-content;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.datagrid {
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
.datagrid-grid {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.datagrid-left {
|
||||
height:100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: auto;
|
||||
}
|
||||
.datagrid-left>.scrollbar {
|
||||
width:0px;
|
||||
opacity:0;
|
||||
}
|
||||
.datagrid-right {
|
||||
flex:1 0 ;
|
||||
height:100%;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.grid_header, .grid_footer {
|
||||
height: 50px;
|
||||
background-color: blue;
|
||||
}
|
||||
.datagrid-row {
|
||||
flex:0 0 150px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.datagrid-body {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
BIN
b/bricks/imgs/add.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
BIN
b/bricks/imgs/checkbox-checked.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
b/bricks/imgs/checkbox-unchecked.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
b/bricks/imgs/delete.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
b/bricks/imgs/delete_node.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
b/bricks/imgs/down_arrow.png
Normal file
|
After Width: | Height: | Size: 6.7 KiB |
BIN
b/bricks/imgs/down_dir.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
b/bricks/imgs/edit.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
b/bricks/imgs/folder.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
b/bricks/imgs/move_bottom.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
b/bricks/imgs/move_down.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
b/bricks/imgs/move_top.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
b/bricks/imgs/move_up.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
b/bricks/imgs/reset.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
b/bricks/imgs/right_arrow.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
b/bricks/imgs/submit.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
56
b/bricks/index.html
Normal 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>
|
||||
|
||||
58
b/bz_order/addbz_order.dspy
Normal file
@ -0,0 +1,58 @@
|
||||
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:
|
||||
users_id = await get_user()
|
||||
user = await sor.R('users', {'id': users_id})
|
||||
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'] = ns.get('userid')
|
||||
bz_ns['customerid'] = orgid[0]['id']
|
||||
bz_ns['order_date'] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
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')
|
||||
nss['unit'] = ns.get('unit')
|
||||
nss['chargeduration'] = ns.get('chargeduration')
|
||||
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
|
||||
158
b/bz_order/affirmbz_order.dspy
Normal file
@ -0,0 +1,158 @@
|
||||
async def cal_expire_time(chargeduration=None, unit=None):
|
||||
chargeduration = int(chargeduration)
|
||||
# 当前时间
|
||||
now = datetime.datetime.now()
|
||||
if unit == 'day':
|
||||
expire_time = now + dateutil.relativedelta.relativedelta(days=chargeduration)
|
||||
elif unit == 'week':
|
||||
expire_time = now + dateutil.relativedelta.relativedelta(weeks=chargeduration)
|
||||
elif unit == 'month':
|
||||
expire_time = now + dateutil.relativedelta.relativedelta(months=chargeduration)
|
||||
elif unit == 'quarter':
|
||||
expire_time = now + dateutil.relativedelta.relativedelta(months=chargeduration * 3)
|
||||
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):
|
||||
"""确认支付"""
|
||||
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_li = await sor.R('product', {'id': order_productid})
|
||||
description = description_li[0]['description'] if description_li else []
|
||||
classify_li = await sor.R('product', {'id': order_productid})
|
||||
classify = classify_li[0]['classify'] if classify_li else ''
|
||||
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:
|
||||
# 计算过期时间
|
||||
chargeduration = j.get('chargeduration')
|
||||
unit = j.get('unit')
|
||||
if chargeduration and unit:
|
||||
expire_time = await cal_expire_time(chargeduration=chargeduration, unit=unit)
|
||||
else:
|
||||
expire_time = None
|
||||
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 %H:%M:%S")
|
||||
if expire_time:
|
||||
nss['expire_date'] = expire_time
|
||||
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)
|
||||
|
||||
# k8s产品 支付成功后创建实例
|
||||
if classify == 'E':
|
||||
spec = json.loads(product[0]['spec_note']) if isinstance(product[0]['spec_note'], str) else product[0]['spec_note']
|
||||
# 映射表,用于将中文字段名转换为英文
|
||||
mapping = {
|
||||
"CPU": "cpu",
|
||||
"内存": "memory",
|
||||
"存储": "storage",
|
||||
"GPU": "gpu",
|
||||
"显存": "gpumem"
|
||||
}
|
||||
# 转换成目标格式的字典
|
||||
k8s_pod_create_ns = {mapping[item["configName"]]: int(item["value"]) for item in spec}
|
||||
k8s_pod_create_ns['orgid'] = orgid[0]['customerid']
|
||||
k8s_pod_create_ns['image'] = 'ubuntu'
|
||||
k8s_pod_create_ns['productid'] = product[0]['id']
|
||||
k8s_pod_create_ns['productname'] = product[0]['name']
|
||||
k8s_pod_create_ns['customer_goods_id'] = nss['id']
|
||||
ks8_result = await path_call('../pub/user_create_pod.dspy', k8s_pod_create_ns)
|
||||
if ks8_result['status']:
|
||||
return {
|
||||
'status': True,
|
||||
'msg': '实例创建成功, 支付操作成功'
|
||||
}
|
||||
else:
|
||||
await sor.rollback()
|
||||
print('k8s实例创建失败, 回滚支付操作')
|
||||
return {
|
||||
'status': False,
|
||||
'msg': '实例创建失败, 回滚支付操作'
|
||||
}
|
||||
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
|
||||
18
b/bz_order/cancelbz_order.dspy
Normal 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/bz_order/chargeback.dspy
Normal 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
|
||||
51
b/bz_order/customer_cartpay.dspy
Normal 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/bz_order/dlebz_order.dspy
Normal 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
|
||||
198
b/bz_order/getbz_order.dspy
Normal file
@ -0,0 +1,198 @@
|
||||
async def getbz_order(ns={}):
|
||||
"""查询订单商品详情,带分页功能"""
|
||||
db = DBPools()
|
||||
async with db.sqlorContext('kboss') as sor:
|
||||
try:
|
||||
users_id = await get_user()
|
||||
if not users_id:
|
||||
server_error(401)
|
||||
|
||||
# 分页参数
|
||||
page = int(ns.get('page', 1))
|
||||
size = int(ns.get('size', 10))
|
||||
offset = (page - 1) * size
|
||||
|
||||
user = await sor.R('users', {'id': users_id, 'del_flg': '0'})
|
||||
orgid = await sor.R('organization', {'id': user[0]['orgid'], 'del_flg': '0'})
|
||||
customerid = orgid[0]['id']
|
||||
|
||||
params = {'customerid': customerid, 'del_flg': '0'}
|
||||
|
||||
# 构建查询SQL,主要查询order_goods并关联bz_order的部分字段
|
||||
sql = """
|
||||
SELECT
|
||||
og.*,
|
||||
bo.customerid,
|
||||
bo.order_date,
|
||||
bo.source,
|
||||
bo.order_status,
|
||||
bo.business_op,
|
||||
bo.ordertype,
|
||||
bo.originalprice,
|
||||
bo.autoreneworder
|
||||
FROM order_goods og
|
||||
JOIN bz_order bo ON og.orderid = bo.id
|
||||
WHERE og.del_flg = '0'
|
||||
AND bo.del_flg = '0'
|
||||
AND bo.customerid = ${customerid}$
|
||||
"""
|
||||
|
||||
# 构建计数SQL
|
||||
count_sql = """
|
||||
SELECT COUNT(*) as total_count
|
||||
FROM order_goods og
|
||||
JOIN bz_order bo ON og.orderid = bo.id
|
||||
WHERE og.del_flg = '0'
|
||||
AND bo.del_flg = '0'
|
||||
AND bo.customerid = ${customerid}$
|
||||
"""
|
||||
|
||||
# # 统计全部 累计支付金额和累计优惠金额 不包含各种筛选条件
|
||||
# # 累计支付金额=BUY+RENEW-BUY_REVERSE实际支付金额 累计优惠金额=BUY+RENEW-BUY_REVERSE优惠金额
|
||||
# total_amount_sql = """
|
||||
# SELECT
|
||||
# COALESCE(SUM(
|
||||
# CASE
|
||||
# WHEN bo.business_op IN ('BUY', 'RENEW') THEN og.amount
|
||||
# WHEN bo.business_op = 'BUY_REVERSE' THEN -og.amount
|
||||
# ELSE 0
|
||||
# END
|
||||
# ), 0) AS total_paid_amount,
|
||||
# COALESCE(SUM(
|
||||
# CASE
|
||||
# WHEN bo.business_op IN ('BUY', 'RENEW') THEN (og.list_price * og.quantity - og.amount)
|
||||
# WHEN bo.business_op = 'BUY_REVERSE' THEN -(og.list_price * og.quantity - og.amount)
|
||||
# ELSE 0
|
||||
# END
|
||||
# ), 0) AS total_discount_amount
|
||||
# FROM order_goods og
|
||||
# JOIN bz_order bo ON og.orderid = bo.id
|
||||
# WHERE og.del_flg = '0'
|
||||
# AND bo.del_flg = '0'
|
||||
# AND bo.customerid = ${customerid}$
|
||||
# """
|
||||
# total_amount_result = await sor.sqlExe(total_amount_sql, {'customerid': customerid})
|
||||
# total_paid_amount = float(total_amount_result[0]['total_paid_amount']) if total_amount_result else 0.0
|
||||
# total_discount_amount = float(total_amount_result[0]['total_discount_amount']) if total_amount_result else 0.0
|
||||
# # 将累计支付金额和累计优惠金额添加到返回结果中
|
||||
# ns['total_paid_amount'] = total_paid_amount
|
||||
# ns['total_discount_amount'] = total_discount_amount
|
||||
# ns['total_count'] = total_count[0]['total_count'] if total_count else 0
|
||||
|
||||
|
||||
# 根据订单号搜索
|
||||
if ns.get('id'):
|
||||
sql += " AND bo.id LIKE ${order_id}$"
|
||||
count_sql += " AND bo.id LIKE ${order_id}$"
|
||||
params['order_id'] = f"%{ns.get('id')}%"
|
||||
|
||||
# 时间范围查询
|
||||
if ns.get('start_time'):
|
||||
sql += " AND bo.order_date >= ${start_time}$"
|
||||
count_sql += " AND bo.order_date >= ${start_time}$"
|
||||
params['start_time'] = ns.get('start_time') + ' 00:00:00'
|
||||
|
||||
if ns.get('end_time'):
|
||||
sql += " AND bo.order_date <= ${end_time}$"
|
||||
count_sql += " AND bo.order_date <= ${end_time}$"
|
||||
params['end_time'] = ns.get('end_time') + ' 23:59:59'
|
||||
|
||||
# 订单状态查询
|
||||
if ns.get('order_status'):
|
||||
sql += " AND bo.order_status = ${order_status}$"
|
||||
count_sql += " AND bo.order_status = ${order_status}$"
|
||||
params['order_status'] = ns.get('order_status')
|
||||
|
||||
# 业务操作筛选business_op BUY, RENEW, BUY_REVERSE
|
||||
if ns.get('business_op'):
|
||||
sql += " AND bo.business_op = ${business_op}$"
|
||||
count_sql += " AND bo.business_op = ${business_op}$"
|
||||
params['business_op'] = ns.get('business_op')
|
||||
|
||||
# 添加排序
|
||||
sql += " ORDER BY bo.order_date DESC"
|
||||
|
||||
# 获取总记录数
|
||||
total_result = await sor.sqlExe(count_sql, params)
|
||||
total_count = total_result[0]['total_count'] if total_result else 0
|
||||
|
||||
# 添加分页
|
||||
sql += " LIMIT ${size}$ OFFSET ${offset}$"
|
||||
params['size'] = size
|
||||
params['offset'] = offset
|
||||
|
||||
# 执行查询
|
||||
order_goods_list = await sor.sqlExe(sql, params)
|
||||
|
||||
if not order_goods_list:
|
||||
return {
|
||||
'status': True,
|
||||
'data': [],
|
||||
'pagination': {'page': page, 'size': size, 'total': 0}
|
||||
}
|
||||
|
||||
# 处理数据
|
||||
for item in order_goods_list:
|
||||
# 清理折扣数据
|
||||
if item['discount'] is None or item['discount'] == 1.0:
|
||||
del item['discount']
|
||||
else:
|
||||
item['discount'] = item['discount'] * 10 # 转换为百分比显示
|
||||
|
||||
# 处理结果中原价list_price和数量quantity 计算总价
|
||||
if item['list_price'] is None:
|
||||
item['list_price'] = 0
|
||||
if item['quantity'] is None:
|
||||
item['quantity'] = 0
|
||||
item['origin_amout'] = float(item['list_price']) * float(item['quantity'])
|
||||
|
||||
|
||||
# 获取产品名称
|
||||
goods = await sor.R('product', {'id': item['productid'], 'del_flg': '0'})
|
||||
if len(goods) >= 1:
|
||||
item['product_name'] = goods[0]['name']
|
||||
item['product_type'] = goods[0]['ptype']
|
||||
|
||||
# 获取产品配置详情
|
||||
item['spec_data'] = None
|
||||
if item.get('spec_id'):
|
||||
specdata_list = await sor.R('specificdata', {'id': item['spec_id'], 'del_flg': '0'})
|
||||
if specdata_list and specdata_list[0]['spec_data']:
|
||||
item['spec_data'] = json.loads(specdata_list[0]['spec_data'])
|
||||
|
||||
# 格式化订单状态
|
||||
status_mapping = {
|
||||
'0': '未支付',
|
||||
'1': '已支付',
|
||||
'2': '已关闭',
|
||||
'3': '已取消',
|
||||
'4': '后付费'
|
||||
}
|
||||
item['order_status_text'] = status_mapping.get(item['order_status'], '未知状态')
|
||||
|
||||
# 格式化业务操作
|
||||
business_op_mapping = {
|
||||
'BUY': '购买',
|
||||
'RENEW': '续费',
|
||||
'BUY_REVERSE': '退款',
|
||||
# 'UPGRADE': '升级'
|
||||
}
|
||||
item['business_op_text'] = business_op_mapping.get(item['business_op'], item['business_op'])
|
||||
|
||||
return {
|
||||
'status': True,
|
||||
'data': order_goods_list,
|
||||
'pagination': {
|
||||
'page': page,
|
||||
'size': size,
|
||||
'total': total_count
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return {'status': False, 'msg': '信息错误: %s' % str(e) + traceback.format_exc()}
|
||||
|
||||
ret = await getbz_order(params_kw)
|
||||
return ret
|
||||
110
b/bz_order/getbz_order_old.dspy
Normal file
@ -0,0 +1,110 @@
|
||||
async def getbz_order(ns={}):
|
||||
"""查询订单详情/我的所有订单"""
|
||||
db = DBPools()
|
||||
async with db.sqlorContext('kboss') as sor:
|
||||
try:
|
||||
users_id = await get_user()
|
||||
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)
|
||||
|
||||
# 兼容第三范式产品展示 这段代码可注释
|
||||
if reacs and reacs[0].get('specdataid'):
|
||||
specdata = await sor.R('specificdata', {'id': reacs[0].get('specdataid'), 'del_flg': '0'})
|
||||
if specdata:
|
||||
specdata_dumps = json.dumps(specdata[0]) if isinstance(specdata[0], dict) else specdata[0]
|
||||
if 'internalip' in specdata_dumps and 'externalip' in specdata_dumps:
|
||||
reacs[0]['spec_data'] = json.loads(json.loads(specdata_dumps)['spec_data'])
|
||||
|
||||
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']
|
||||
i['discount'] = i['discount'] * 10 if i.get('discount') else None
|
||||
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': users_id, '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': users_id, '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'})
|
||||
actual_all_price = 0
|
||||
for j in reacs:
|
||||
reacsgoods = await sor.R('order_goods', {'orderid': j['id'], 'del_flg': '0'})
|
||||
all_price = 0
|
||||
countlist_price = 0
|
||||
business_op = j['business_op']
|
||||
for i in reacsgoods:
|
||||
if i['discount'] == None or i['discount'] == 1.0:
|
||||
del i['discount']
|
||||
i['discount'] = i['discount'] * 10 if i.get('discount') else None
|
||||
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'] * i['quantity']
|
||||
actual_price = i['price'] * i['quantity']
|
||||
# countlist_price += i['list_price']
|
||||
# countlist_price *= i['quantity']
|
||||
if j['order_status'] == '1':
|
||||
all_price += countlist_price
|
||||
if business_op != 'BUY_REVERSE':
|
||||
actual_all_price += actual_price
|
||||
j['countprice'] = round(all_price,2)
|
||||
if j['countprice'] == 0:
|
||||
j['countprice'] = j['originalprice']
|
||||
return {'status': True, 'data': reacs,'all_price': round(actual_all_price,2)}
|
||||
except Exception as e:
|
||||
raise e
|
||||
return {'status': False, 'msg': '信息错误'}
|
||||
|
||||
ret = await getbz_order(params_kw)
|
||||
return ret
|
||||
56
b/bz_order/index.html
Normal 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/bz_order/upbz_order.dspy
Normal 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
|
||||