Former-commit-id: 1ce264e768be19765848e792a2a369e4bcf5ab22 [formerly 835a3b2abcc7d02ce4501ca12e4fe641aa7c45e5] [formerly 43c8461f948d9ba930aba59f7b93e08af37917ec [formerly ecd43f50bd1f11e3ca841096e309f9052f73be46]] [formerly 9dad89c6c83a4f5d29fcbb41ba71021a9c5f278d [formerly 8e839f4f42b2ed01b6b31755d1d0c5c65d448a8f] [formerly e70e01e1731bbe9ff022d8f4ab917da435e10981 [formerly a6ef0cf96d3b4ad3173569c3034d435b68bc61fb]]] [formerly 7bd03c373e494a773d59468b1bb8c139e4780890 [formerly 6979daf92b6a517e0c11070e6fb724654c28358b] [formerly 7bd03c373e494a773d59468b1bb8c139e4780890 [formerly 6979daf92b6a517e0c11070e6fb724654c28358b] [formerly b9b738f8675c3b22a77f6b191c4a06cc23f31b1d [formerly 53ec5b6de9b8d1199377ac15c08f9d62ae5b8444]]]] [formerly 8278d8b0303b2c4a1da42e6594694bd70615bfff [formerly 5af8152a882db06050a7dd31eb6e8a12d6c62dd3] [formerly 8278d8b0303b2c4a1da42e6594694bd70615bfff [formerly 5af8152a882db06050a7dd31eb6e8a12d6c62dd3] [formerly efe021b0d1996a738668af58cfc7da5993462ff4 [formerly db301edd777df6601a416ccc049f9db2c19b4292]]] [formerly 7bd03c373e494a773d59468b1bb8c139e4780890 [formerly 6979daf92b6a517e0c11070e6fb724654c28358b] [formerly b9b738f8675c3b22a77f6b191c4a06cc23f31b1d [formerly 53ec5b6de9b8d1199377ac15c08f9d62ae5b8444]] [formerly b9b738f8675c3b22a77f6b191c4a06cc23f31b1d [formerly 53ec5b6de9b8d1199377ac15c08f9d62ae5b8444] [formerly 0b669f5694112ae03fe33d4df5fc80338db90035 [formerly 8eebf943a86c60a8d1ddda4df331d89f6f359683]]]]] [formerly 4a05aa1c5b584af4e70cbd24828cc0dc2fa6a249 [formerly 8e3d6065566b6feda200b0c2920b449ce04a4f8d] [formerly 4a05aa1c5b584af4e70cbd24828cc0dc2fa6a249 [formerly 8e3d6065566b6feda200b0c2920b449ce04a4f8d] [formerly 0167dd77e345ab95dbea33dafb157856d99cfd02 [formerly e11a0c94b6853554b8ee0b01382aef49b1830d01]]] [formerly 080ed9b8dda9038c695fb15d84a80bf6fed13ec4 [formerly 93655f5d1d39c146038b8185703017d2fe2d7a3b]] [formerly b1113cd5d16436f0c0f64b8338ed23ecae131515 [formerly c6e057881b651cb243e73609db6b9b4bed51a878] [formerly b1113cd5d16436f0c0f64b8338ed23ecae131515 [formerly c6e057881b651cb243e73609db6b9b4bed51a878] [formerly 167fb27fba78a5f698441901097916581c6404b0 [formerly 2b7b66d03e3d0e55b4aacca370b347e89740817b]]] [formerly 080ed9b8dda9038c695fb15d84a80bf6fed13ec4 [formerly 93655f5d1d39c146038b8185703017d2fe2d7a3b] [formerly 080ed9b8dda9038c695fb15d84a80bf6fed13ec4 [formerly 93655f5d1d39c146038b8185703017d2fe2d7a3b] [formerly c00d1b174e6232be1054873a03ca8321af28472e [formerly ba37d6315e15212ee818e728e7acdbde2454dc07 [formerly aa8f50ecc422ecd5a8816823128fdbf004e212a5] [formerly 81014c254ca2d5bbdb3ea5cd0cfecf220e7d319a [formerly 986fa9b65ab1acd22ea51ba91aa9fe48be2d1253]] [formerly e2adef2d3c2a610aba0b3e8afdf6a206ab1b6157 [formerly 8333b363032ec2038a6d08067246fb133b0d2885] [formerly 0fd360620afd8ec8484bce5c921feb2a7a7d37d9]] [formerly 0fd360620afd8ec8484bce5c921feb2a7a7d37d9 [formerly 3fd364606d971551f50ab5297eed680d51dc60c1]] [formerly b7162540d4bf13a6990d488bc5763429f5ea209b [formerly 0fd360620afd8ec8484bce5c921feb2a7a7d37d9 [formerly 3fd364606d971551f50ab5297eed680d51dc60c1] [formerly b7162540d4bf13a6990d488bc5763429f5ea209b [formerly d26c38804c560be5d9e7f051766e71539c128f10 [formerly cf1f0e0c58bbabdbc2735c8a7fd85b07bc601845] [formerly b7162540d4bf13a6990d488bc5763429f5ea209b [formerly f04f0e33a5]]]]]]]]]]]]
Former-commit-id: ec50f9de7f1b5d56747338a018f88fc5228567f1 [formerly 404933efe07b8fb158a3a7b03bde648afee9df80] [formerly 6a665fa2ae3a6c47a99c40000e7b6864592a7dac [formerly f700e146855839d85aacc60644fc02b64478a3ba]] [formerly 0a894c11a40eeccf4a570a26ef93343797fc36d5 [formerly 1599df40c0f2b6a51af13fb85f5e9edb485a6802] [formerly a483e7f693f410cac224400d1228af4ca8e81f8c [formerly 45e3f2099d96a32983bdfeb5e0c4eeeee8bae743]]] [formerly ff96f1c62461efe685c3f8069ed02a60e7fd20fd [formerly 597b9b9028d5879f2ee4ef9e1157697bcb2c4689]] [formerly 4f3939a02eaf94745ee59cae2c377ba01bfdd0a2 [formerly 14acbdd1e884559f66f1d8ddb0cbdcee8fa2af1e] [formerly 4f3939a02eaf94745ee59cae2c377ba01bfdd0a2 [formerly 14acbdd1e884559f66f1d8ddb0cbdcee8fa2af1e] [formerly aa59ff3c18eef08aa6d0f59b098619858527800b [formerly fea1d34dd71239752c3ce58b63881211ce2bd18c]]] [formerly ff96f1c62461efe685c3f8069ed02a60e7fd20fd [formerly 597b9b9028d5879f2ee4ef9e1157697bcb2c4689] [formerly ff96f1c62461efe685c3f8069ed02a60e7fd20fd [formerly 597b9b9028d5879f2ee4ef9e1157697bcb2c4689] [formerly ba963f2b1b38ef24fa5a6f506bb5105de672a08f [formerly 577bf2a6a365de54bd7fc306274fff2135deb991]]]]]
Former-commit-id: eea674bfc0f88b7d8ce45e76956c10a687e71642 [formerly cec885680849b1af76998d4fb19d3056de7ee85b] [formerly 9eb89164bea30a7b45f63248a4b368d7bfc18d69 [formerly ecc6ed08365110ab03d38c8d78652635aecdf9f4]] [formerly 9eb89164bea30a7b45f63248a4b368d7bfc18d69 [formerly ecc6ed08365110ab03d38c8d78652635aecdf9f4] [formerly 32e2aa48b5d475d10fc30712ac18ee9a9c097533 [formerly a7b98f94df3f3dad11f19883691d42621d6ebac4]]] [formerly 4a2b62e5587f0622136c41de0725dfabe963e759 [formerly c1b9a4193d558d3186aed1611dd43df9dd9ec813] [formerly 4a2b62e5587f0622136c41de0725dfabe963e759 [formerly c1b9a4193d558d3186aed1611dd43df9dd9ec813] [formerly 0d8c4276a122a1ea22d5049058e44bdb497f9d64 [formerly ad49c5a35584cec535208eeb552f9b986ae92ab3]]]]
Former-commit-id: 4a2b62e5587f0622136c41de0725dfabe963e759 [formerly c1b9a4193d558d3186aed1611dd43df9dd9ec813]
Former-commit-id: 273c338308585e5b5066c46de4b9ba99fccb0e49 [formerly 9d136b4ce28189a743e36273c03c9c85c57936a0] [formerly 2ea7c121e6b19f89cd7dae4fbc5b1cf2fdaaea13 [formerly f99a7cdd51c969579cec97a07e80f3d20fe1caef]]
Former-commit-id: dc9a556bf8f17ca69fc9f008bbd11f2469d08df3 [formerly 87c99130bf6a4612a6329cf0cb658a522d9e9b10]
Former-commit-id: 1540286f7a4f6a7ff234ef84a2188c3e21a11a15
Former-commit-id: e1b4f6fce12993e8a9b9b6645fdc1f0b457e8558 [formerly b086d6a2574172e8651165f7e54ec23c869bb5c8]
Former-commit-id: d2fa79438ae5f490990e2e30f23307dbcc1b0557
Former-commit-id: 7211af68ca [formerly 1c2ad6eb8608ac0d463f41d5d8e3c31e31badace] [formerly 3a517145e23d33fae7e18e2f97453d7c77f4f3fb [formerly 66e42a6a5eae1d16d85b61fac274b37f038db72c]] [formerly 08b8e7d564824db98df493d47c16823e490ad388] [formerly ac51e50dd8af9ac51b02b9a9dfd6ef097d31a512 [formerly 54f33b056777e170777c66f63635c026cb2f4502 [formerly 4e52795127b5b1398a5195c5d93b9e87471861e5] [formerly aaff0707950912c85783267280fd38c92dcebb20 [formerly a29f989feca024cfc0c70db3e80240d7cfa604ba]]]]
Former-commit-id: b3b10e94bb3fada54e515ebbb430c6f8d186da04 [formerly fbf0518e2b8258c3b8459aa0c686e708fb93c27f [formerly 22d10feca8741db1b4d3174a8939b4ae8b5dbbb7] [formerly d88eaf73ca79f73ee58c92a95166874b8dce4667 [formerly 6fe9c8b17e57c68d3b9941a478ffc2a5c996c48a]]]
Former-commit-id: 70d26085f499e64417ecf0e6637e5a6cf355e794
Former-commit-id: 041f98dc0b352494b6b82d90ec476dc6aabf9f32 [formerly ff5484880b2bf6c5e1c00dc41a3458d50e020786]
Former-commit-id: ca826858f49845c7dd7f56946b2b2483b3207b58
This commit is contained in:
Elvis.Shi
2022-04-03 09:31:29 +08:00
parent 04d54a546e
commit f16b230e3e
1838 changed files with 0 additions and 167845 deletions
-1
View File
@@ -1 +0,0 @@
*.vue linguist-language=python
-12
View File
@@ -1,12 +0,0 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: ['paypal.me/singosgu/1usd']
-8
View File
@@ -1,8 +0,0 @@
node_modules/
__pycache__/
authorization.txt
authorization.json
db.sqlite3
.idea/
delete.py
*.xlsx
-40
View File
@@ -1,40 +0,0 @@
~~~shell
如何配置Cordova环境,请参考
http://www.quasarchs.com/quasar-cli/developing-cordova-apps/preparation
# 进入templates目录,创建src-cordova
quasar mode add cordova
# 进入src-cordova目录
cd src-cordova
# 部署安卓客户端
cordova platform add android
输入app名称为org.greaterwms.app
# 返回templates目录,先启动一次项目来创建gradle文件夹
quasar d -m cordova -T android
Ctrl + c退出
# 修改gradle版本下载distributionUrl,文件在tempates/src-cordova/platforms/android/gradle/wrapper/gradle-wrapper.properties
distributionUrl=https://mirrors.cloud.tencent.com/gradle/gradle-4.10.3-all.zip
# 进入src-cordova目录来安装所需要的插件
cd src-cordova
# 按顺序安装插件
cordova plugin add cordova-plugin-device
cordova plugin add cordova-plugin-battery-status
cordova plugin add cordova-plugin-camera
cordova plugin add com-darryncampbell-cordova-plugin-intent
cordova plugin add https://gitee.com/Singosgu/cordova-plugin-ubx.git
# 修改适配问题的文件,templates\src-cordova\platforms\android\app\src\main\java\org\apache\cordova\camera\FileProvider.java
第21行的android.support.v4.content.FileProvider,修改为androidx.core.content.FileProvider
# 修改适配问题的文件,templates\src-cordova\platforms\android\app\src\main\java\org\apache\cordova\camera\CameraLauncher.java
第42行的android.support.v4.content.FileProvider,修改为androidx.core.content.FileProvider
# 回到templates,再次启动项目
quasar d -m cordova -T android
现在只支持Zebra扫描枪,Zebra扫描枪需要打开广播
Zebra扫描枪配置请看:
https://github.com/Singosgu/GreaterWMS/blob/master/Zebra-Profile.pdf
# 打包apk
quasar build -m android
接下来在dist/cordova/android/apk/release下面可以找到一个未签名的apk,关于怎么签名,自行百度
~~~
-71
View File
@@ -1,71 +0,0 @@
~~~shell
su - // 进入管理员账号
yum update
yum upgrade
yum -y install gcc-c++ // 安装依赖
yum install zlib-devel xz-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel libffi-devel gcc make // 安装python依赖
yum install nodejs // 安装nodejs
npm install n -g // 安装n
/usr/local/bin/n 14.18.3 // 升级nodejs
npm install npm -g // 升级npm
npm install yarn -g // 安装yarn
npm install @quasar/cli -g // 安装quasar
npm install cordova -g // 安装cordova
quasar -v // 检查 Quasar 版本
python3 // 查看python版本
cd /usr/src // 进入src
wget https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tgz // 下载python3.9.5
tar -zxvf Python-3.9.5.tgz // 解压
cd Python-3.9.5/ // 进入目录
./configure --enable-optimizations // 编译
make altinstall // 安装
mv /usr/bin/python3 /usr/bin/python3.bak // 备份
ln -s /usr/local/bin/python3.9 /usr/bin/python3 // 建立软连接
mv /usr/bin/pip3 /usr/bin/pip3.bak // 备份
ln -s /usr/local/bin/pip3.9 /usr/bin/pip3 // 建立软连接
python3 // 查看python版本
pip3 list // 查看pip3 是否安装成功
yum install git // 安装git
git clone https://github.com/Singosgu/GreaterWMS.git // 下载 GreaterWMS 从 github
chmod -R 755 GreaterWMS // 提权 GreaterWMS 文件夹
cd GreaterWMS // 进入GreaterWMS文件夹
pip3 install -r requirements.txt
// 有些时候,你安装这些库会出问题,是因为python3版本的问题,不用担心,pip3 install 出错的库就可以了.
/usr/local/bin/daphne -p 8008 greaterwms.asgi:application
// 现在打开浏览器,输入"127.0.0.1:8008",你会看到500错误,恭喜你,你已经可以正常部署接下来的事情了
Ctrl + C // 回到GreaterWMS文件夹
python3 manage.py makemigrations // 数据库生成
python3 manage.py migrate // 数据库迁移
/usr/local/bin/daphne -p 8008 greaterwms.asgi:application
// 现在打开浏览器,输入"127.0.0.1:8008",你会看到项目已经运行了
// 输入 "127.0.0.1:8008/myip", 你会得到你的内网IP,一定记住它
Ctrl + C // 回到GreaterWMS文件夹
cd templates //进入 templates 文件夹
/usr/local/bin/yarn install // 等待Yarn安装完成,其实你也可以npm install ,就是会慢一点
yarn config set registry https://registry.npm.taobao.org/ //更改yarn为国内源
/usr/local/bin/quasar d // 使用quasar命令启动前端页面
// 前端会向 "127.0.0.1:8008"发请求, 在这里我们只是看下项目是不是可以运行
Ctrl + C // 退回到templates文件夹
从2.0.19版本以后,优化了请求地址修改方式,直接修改templates/dist/spa/statics/baseurl.js,中的baseurl和wsurl,就可以成功更改前端请求地址,不再需要做下面的quasar build打包工作。
如果需要修改前端内容,则还需要修改templates/public/statics/baseurl.js中的baseurl和wsurl,然后重新使用quasar build进行打包
cd src/boot // 进入在src/boot文件夹
vim axios_request.js // 我们开始更改请求地址
// 更改 "127.0.0.1" 成你的内网IP, baseurl 是http请求地址 , ws 是 websocket请求地址
按下 Esc 然后输入 ":wq" 去保存修改
// 现在,你已经知道怎么部署和修改请求地址了
/usr/local/bin/quasar build // 需要对修改进行重新打包
cd .. // 回到GreaterWMS文件夹
/usr/local/bin/daphne -b 0.0.0.0 -p 8008 greaterwms.asgi:application
// 现在,打开浏览器,输入 "你的内网IP:8008",你可以看到项目已经运行了
谢天谢地!!!
顺便说一句
1. 你知道了怎么修改请求地址
2. 你也可以按你的喜好,去更改Port
3. 你更可以使用Nginx或者Apache,把项目发布到互联网上
~~~
-45
View File
@@ -1,45 +0,0 @@
~~~shell
su - // Enter root
yum update
yum upgrade
yum -y install gcc-c++
yum install zlib-devel xz-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel libffi-devel gcc make
yum install nodejs
npm install n -g
/usr/local/bin/n 14.18.3 // update nodejs
npm install npm -g
npm install yarn -g
npm install @quasar/cli -g
npm install cordova -g
cd /usr/src
wget https://www.python.org/ftp/python/3.9.5/Python-3.9.5.tgz // download python3.9.5
tar -zxvf Python-3.9.5.tgz
cd Python-3.9.5/
./configure --enable-optimizations
make altinstall
mv /usr/bin/python3 /usr/bin/python3.bak // backup python3
ln -s /usr/local/bin/python3.9 /usr/bin/python3
mv /usr/bin/pip3 /usr/bin/pip3.bak // backup pip3
ln -s /usr/local/bin/pip3.9 /usr/bin/pip3
yum install git // install git
git clone https://github.com/Singosgu/GreaterWMS.git // clone GreaterWMS from github
chmod -R 755 GreaterWMS
cd GreaterWMS
pip3 install -r requirements.txt
python3 manage.py makemigrations
python3 manage.py migrate
/usr/local/bin/daphne -p 8008 greaterwms.asgi:application
// open Chrom "127.0.0.1:8008/myip", you will get your internal lan ip, remember it
Ctrl + C // back GreaterWMS folder
cd templates // enter templates folder
/usr/local/bin/yarn install
/usr/local/bin/quasar d // it will start web site
Ctrl + C // back templates folder
cd src/boot
vim axios_request.js // change request baseurl
// change "127.0.0.1" to your internal IP, baseurl is for http, ws is for websocket
// save it
/usr/local/bin/quasar build // build your web site
cd .. // back to GreaterWMS folder
/usr/local/bin/daphne -b 0.0.0.0 -p 8008 greaterwms.asgi:application
// nowyou can use "internal IP:8008" to use greaterwms
@@ -1 +0,0 @@
22a265356ea69c3d30d96cfaaa591988adcc37b1
@@ -1 +0,0 @@
e1c14c564fee6800193b329912b295539a0f39ce
-202
View File
@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
https://www.56yhz.com
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-1
View File
@@ -1 +0,0 @@
3ea6e343625852897cca8991854acf08d3f46700
-337
View File
@@ -1,337 +0,0 @@
# GreaterWMS--Open Source Warehouse Management System
<p><div align=center><img width="150" height="150" src="https://github.com/Singosgu/GreaterWMS/blob/master/static/img/logo.png?raw=true?raw=true"/></div></p>
---
[中文文档](https://github.com/Singosgu/GreaterWMS/blob/master/README_zh_Hans.md)
## Production Introduce:
Fully open source warehouse management system follows Apache License 2.0 and front-back stage decoupling method. API uses restful protocol to facilitate for add-on functions development. The html & js code is constructed with quasar(base on Vue.js v2.6.0+). According to API, it can support business models such as multi warehouse, wave shipment, combined picking and milk-run and so on.
- Software Copyright Procedures: 10136559
- GitHub Link: [GitHub](https://github.com/Singosgu/GreaterWMS)
- Gitee Link: [Gitee](https://gitee.com/Singosgu/GreaterWMS)
- Video Tutorials: [YouTube](https://www.youtube.com/channel/UCPW1wciGMIEh7CYOdLnsloA)(All Tutorials Will Upload To Here)
- Home Page: [DEMO](https://www.56yhz.com/)(Register can initial the demo data)
- Mailmail@56yhz.com
- CIMO-ADMIN(vue-quasar-manage): [GitHub](https://github.com/972784674t/vue-quasar-manage) | [Gitee](https://gitee.com/incimo/vue-quasar-manage)
---
## Our Original Intention:
I have 15 years old experience focus on supply chain . I find that in this professional field . No freedom customize software can support our business deeply . Any software are closed-source and hardly to customize or dynamic with our suppliers & customers . So I design GreaterWMS , in order to give business highest freedom way to support trade development .
- Our Vision: If you work in a non IT industry and you love your industry, please using technology to change it.
---
## Development Environment:
- Python Version 3.9.5 +
- Django Version 3.1.12 +(This version of Django only supports asynchronous real-time communication)
- Django-rest-framework Version 3.12.2 + (Highest versions of Django-rest-framework are more compatible with Django3)
- Django-silk Version 4.1.0 (If you are deploying production, please turn off silk, which is only used for debugging API interface speed, which may leak users' information)
- Quasar Version 1.7.2 + (You can view the official website of quasar to edit the webside code of greater WMS: [Quasar](https://quasar.dev/))
- Vue Version 2.6.0 +Try not to use vue3, because the development environment does not use vue3, I don't know what will happened
- APIFollow RESTful
---
## Build Command:
- Git Clone:
~~~shell
git clone https://github.com/Singosgu/GreaterWMS.git
~~~
- Install Python Library:
~~~python
pip install -r requirements.txt
~~~
Atention: `Installation requires Twisted library, this library sometimes cannot be installed, you need to download it and install it locally`
- Download Link[TWISTED](https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted)
~~~python
pip install Twisted{Version Name Which You Download}
~~~
Atention: `Local installation needs to pay attention to the path`
- Makemigrations the Database:
~~~python
python manage.py makemigrations
~~~
- Migrate Database:
~~~python
python manage.py migrate
~~~
Create a database. Django uses sqlite3 as the default database. If you need other database, please configure DATABASE in greaterwms/settings.py
### Run Development Server:
- Dev Run
~~~python
daphne -p 8008 greaterwms.asgi:application
~~~
### Run Production Server:
- supervisor Daemon:
~~~shell
pip install supervisor
~~~
Use supervisor to guard the Django process, and then use Nginx as a reverse proxy. As for supervisors, there are many tutorials, so I wont explain them here.
- Nginx Support:
It is recommended to use Nginx for deployment. You need to specify the WebSocket link when deploying. If you do not specify it, the real-time communication function will report an error.
Also need to modify ws_url in templates/dist/spa/statics/baseurl.js
~~~shell
## Example changes before
const baseurl = 'http://127.0.0.1:8008/'
const wsurl = 'ws://127.0.0.1:8008/'
## Example changes after
const baseurl = 'https://Your Production Server/'
const wsurl = 'wss://Your Production Server/websocket/'
~~~
If the server has SSL enabled, please use https and wss, if SSL is not enabled, use http and ws
The front-end code needs to be rebuilt after modification
---
## Development Guide:
### Baseurl
- It is the basic URL for initiating the request. If it is for local debugging, the default is http://127.0.0.1:8008/. If it is deployed on the server, you need to change it to your website access URL
- The modification method is to modify axios_request.js. Attention: `The modification of websocket has been mentioned `
### Django-Silk
- Django-Silk is a debugging tool during development. It can count the response speed of each interface. If you need to deploy to a production environment, please delete the Django-silk related configuration, because there is a risk of leaking user information, or directly modify the Django-silk library , So that users can only see their request data
### Database Storage
- Data migration and other issues are considered during database design, so only the user_id in users and the user_id that comes with Django are foreign keys, and all the other fields do not use foreign keys, which is convenient for data backup and database migration.
- The database is a 4-stage design
1. Verify data user ownership
2. Verify data security
3. Verify that the data can be stored in the database
4. Save it in the database and return Response
### About Data Request
- The token value needs to be added to all request headers. This value is the unique identifier OPENID of the users data
- All data transmission needs to set content-type to application/json
### OPENID
- OPENID is the unique identifier of registered user data. When the administrator registers directly, there will be developer=1 as the administrator ID.
- You can do custom secondary development based on the developer label
### APPID
- APPID is the unique identifier of the user data group
- If you need multi company operation or multi warehouse operation, you can make unified link through appid to realize multi company and multi warehouse operation
### User Jurisdiction
- There are not too many restrictions on user authorization. Please limit the secondary development according to your own business needs
---
## Business Process:
### Administrator
- Click Register, you can register as an administrator account, so as to realize the initialization program settings
- After registration, you will get two IDs and one developer label. openid is the unique ID of the user data group. All data under this openid is bound through openid. Appid is the unique ID of the user group data. Multi company and multi warehouse functions are realized through appid. The developer ID is a Boolean value, and true represents an administrator account
- There are two way for user login:
1. Login directly with openid and staff name
2. Administrator login with account and password
- After login, the web will localstorage login information
- you can view the openid of user data group by view my openid
- If multi company and multi warehouse operation is required, pay attention to change openid
- More administrator authrization, please develop by yourself
### Staff
- After registering as an administrator, create a new staff first
- Staff has two fields, staff_ Name (for employee login), staff_ Type (employee type to control employee permissions)
- The system does not have any restrictions on employee permissions. If you need employee permissions, please modify them according to the enterprise business model Templates
- Click Edit to modify the employee information
- Click Delete to delete the staff information. The system will set is_delete to true
- Click Contact:
1. You can directly chat with employees in real time, but you can't chat with yourself
2. You can create a new notebook employee, which is actually used as a notebook
3. In the personal center, you can view recent contacts
4. The message flag will remind you how many unread messages you have
### Driver
- Driver management is only used in the shipping process
- You need to know which driver picked up the goods
### Warehouse Set
- Warehouse
1. You can create only one warehouse. Now you can create multiple warehouses, but only the first one will work
2. If multi warehouse processing is needed, secondary development can be carried out through appid, or an administrator account can be created directly
3. The city of the warehouse must be filled in, which is used to calculate the freight
- Bin_Property
1. The bin property determines the property of the goods in the warehouse
2. Four property: damage, holding, inspection, normal
3. In the beta version, property can be modified and deleted, but the release version can not
4. All shipping process will only match the goods in the normal bin
5. When goods are received and moved to another bin, the inventory quantity will be directly modified according to the bin property, and the inventory quantity of the warehouse will not be negative
- Bin_Size
1. The size of bin is to help the operator to check whether the goods can be put into the bin
2. The current version does not check the dimensions of bin, and automatic inspection will be added in the future
- Bin_Set
1. Bin setting is necessary. Generally, bin setting is horizontal, vertical and horizontal, such as A010101, i.e. A horizontal, 01 vertical, 01 horizontal and 01 vertical
2. The setting of bin needs to set the bin property and size. The property is very important, which determines whether the goods in this bin are normal goods
### Basic Info
- Company
1. The creation of basic company information can only create one company. Now you can create multiple companies, but only the first one will work
2. If multi company processing is needed, secondary development can be carried out through appid, or an administrator account can be created directly
3. The city of the company must be filled in, which is used to show on the receipt-proof
- Supplier
1. Basic information of suppliers
2. The city of the supplier must be filled in, which is used to display on the receipt-proof, and also to calculate the freight automatically
- Customer
1. Basic information of customers
2. The customer's city must be filled in, which is used to display on the invoice, and also to automatically calculate the freight
### Godds
- Unit
1. Goods units, the system will initialize to create some, but you can add and modify
- Class
1. Goods Class, you can add and modify
- Color
1. Goods color, the system will initialize to create some, but you can add and modify
- Brand
1. Goods brand, you can add and modify
- Shape
1. Goods Shape, the system will initialize to create some, but you can add and modify
- Specs
1. Goods specs, you can add and modify
- Origin
1. Goods Origin, where initial product goods, you can add and modify
- Goods List
1. Goods list
### Capital
- Capital
1. The creation of fixed assets, not too much expansion, just record the use
2. Can be statistical pallets accounts
### Stock Management
- Stock List
1. Total inventory data of goods
2. Onhand_ Stock quantity on hand
3. Can order, which can be used to determine the inventory quantity of an order. Some goods have been ordered, but they can't be ordered any more even though they have existing inventory
4. Ordered stock, the quantity of goods be ordered
5. ASN stock has issued the arrival notice, but has not confirmed the quantity of goods in the arrival notice
6. DN stock, has been ordered, but the order quantity has not been confirmed
7. Pre Load,expected quantity of goods delivered
8. Pre Sort,the quantity of goods that have arrived, unloaded and waiting to be sorted
9. Sorted Stock, The quantity of goods waiting to be put on the bin after sorting
10. Pick Stock, The picking list is generated from the delivery document, and the quantity of goods waiting to be picked
11. Picked Stock The quantity of goods that have been picked up and waiting to be handed over to the driver
12. Back Order Stock, Order quantity in arrears
- Bin Stock
1. Total Stock, all inventory quantities of the product in this bin
2. Pick Stock, the quantity of goods to be picked in this bin
3. Picked stock, the quantity of goods picked in this bin
4. Move to Bin: after moving, the inventory quantity will be updated directly according to the bin property. If all goods has been moved out from this bin, the bin will be updated to empty
- Empty Bin
1. Empty bin List
- Occupied Bin
1. Occupied bin list
### Inbound
- ASN
1. ASN status = 1, the ASN arrival notice is created, and status 1 is the only status that can delete and modify the ASN information. It will be displayed in pre delivery, that is, there is an arrival notice, but it has not arrived. Click confirm delivery to confirm that the goods have arrived, and ASN status will be updated to 2. At this time, the ASN information can no longer be modified
2. ASN status = 2, it is developed to queue up for the arrival of drivers. If we have many drivers arriving, it can be made into a queuing system. At the same time, it can also let the purchase and sales see the arrival information, reduce unnecessary email and telephone communication. Click finish loading to confirm that the goods have been unloaded, and Asn status will be updated to 3, The goods information will appear in sorting, and the ASN status indicates that the goods have been unloaded to the warehouse and are waiting for sorting
3. ASN status = 3, goods sorting is a necessary process. Without goods sorting, goods cannot be put on shelves. The principle of putting on shelves is to arrange the goods and put them on the corresponding warehouse location. Click confirm sorted, and Asn status will be updated to 4, that is, confirm the sorting and wait for loading
4. At this time, when you move the sorted page, the goods details that need to be put on the shelves will appear. Click move to bin to finish the listing. Of course, the system will automatically update the inventory quantity information of goods according to the location attributes after the listing
### Outbound
- DN
1. DN status = 1, when the DN shipping order is created, the order status can still be modified, and the inventory quantity in the system will not change. Click confirm order, and the DN status will be updated to 2, that is, the order has been confirmed and cannot be changed. At the same time, the inventory quantity in the system will be automatically updated, such as can order quantity and ordered quantity
2. DN Status = 2, This is the process when an order is confirmed and waiting to generate a picking list. You can click order release of a single order to generate a picking list of an order. You can also click release all order to generate a picking list of all orders. If all orders are released, the inventory will be matched according to the time sequence. When the inventory is insufficient, back will be generated In this process, the DN order number will change. For example, multiple orders of a customer will be unified into one order for picking. If the customer's order cannot be satisfied, the unsatisfied part will be generated as a shortage order. If the shortage order is not met by the matched inventory, no new order will be generated. Dn The status will be updated to 3, that is, in the process of waiting for picking, the status will be 2 when both the confirmed order and the shortage order are in the same status
3. DN Status = 3,Direct picking, this function will appear in beta5 update
4. DN Status = 4, Delivery handover, this function will appear in beta6 update
5. DN Status = 5, Customer receiving, this function will appear in beta7 update
6. DN Status = 6, When the reconciliation is finished and the order is closed, this function will appear in the beta7 update
### Reject Order
- RO
This feature will add in the release version
### Screen Shot
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/inbound.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/outbound.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/stock.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/finace.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/goods.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/baseinfo.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/warehouse.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/staff.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/driver.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/api.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/chat.png?raw=true"/></div></p>
<p><div align=center><img src="https://github.com/Singosgu/picfile/blob/master/CN/app1.png?raw=true"/></div></p>
<p><div align=center><img src="https://github.com/Singosgu/picfile/blob/master/CN/app2.png?raw=true"/></div></p>
<p><div align=center><img src="https://github.com/Singosgu/picfile/blob/master/CN/app3.png?raw=true"/></div></p>
<p><div align=center><img src="https://github.com/Singosgu/picfile/blob/master/CN/app4.png?raw=true"/></div></p>
-395
View File
@@ -1,395 +0,0 @@
# 聚商汇WMS--开源仓库管理系统
<p><div align=center><img width="150" height="150" src="https://github.com/Singosgu/GreaterWMS/blob/master/static/img/logo.png?raw=true?raw=true"/></div></p>
---
## 项目介绍:
完全开源仓储管理软件,遵循Apache License 2.0协议,前后端分离,且完全开源,API使用restful协议,方便二次开发,前端代码使用quasar进行构建,后端使用Python Django3.1,利用API,可以支持多仓,波次发货,合并拣货,Milk-Run等业务模型。
- 软件著作权编号:2018SR517685
- GitHub地址:[GitHub](https://github.com/Singosgu/GreaterWMS)
- Gitee地址:[Gitee](https://gitee.com/Singosgu/GreaterWMS)
- 视频教程:[B站](https://space.bilibili.com/407321291/channel/detail?cid=152043)(所有的教程都会更新在这里)
- Demo地址:[DEMO](https://www.56yhz.com/)(注册会获得初始化Demo数据)
- 技术交流群:![wechat.png](https://github.com/Singosgu/picfile/blob/master/CN/wechat.png?raw=true)
- 邮箱:mail@56yhz.com
- CIMO-ADMIN(vue-quasar-manage): [GitHub](https://github.com/972784674t/vue-quasar-manage) | [Gitee](https://gitee.com/incimo/vue-quasar-manage)
---
## 项目初衷:
我在供应链行业工作了15年,发现在我们这个专业的领域,没有一款高自由度、高自定义化的软件,来深度支持我们企业的业务。大多数软件都是闭源的,而且很难去做二次开发,即使开发,周期也是非常长,开发失败的案例也是比比皆是。由于企业选择了一款软件后,其二次开发也会被开发公司绑定,至于二次开发费用,只能说呵呵。所以,我设计了这个聚商汇WMS,为的是做到一款高自由度,高自定义开发的仓库管理软件,来深度支持企业的业务。
- 愿景:如果你从事着非IT行业的工作,而你又热爱你的行业,那就用科技去改变他。
---
## 生命周期
- V 1.0.0 -- 2019年7月 ~ 2020年12月(由于1.0.0版本的二次开发设计较为复杂,故2.0重新编写)
- V 2.0.0 -- 2020年12月 ~ 2021年3月(重新编写业务逻辑,原生自带API开发文档,加入实时通信,方便企业用户互相沟通)
- V 2.1.0 -- 2021年3月 ~ 2021年6月(加入了客户与企业之间的实时互动,增进企业与客户之间的业务联系,实现VMI)
- V 2.2.0 -- 2020年6月 ~ 2021年9月(加入了供应商与企业之间的实时互动,增进企业与供应商之间的业务联系,实现Milk-Run和看板拉动)
- V 2.3.0 -- 2021年9月 ~ 2021年12月(库存管理雏形,初步加入神经网络,深度学习库存变化)
- V 3.0.0 -- 2021年12月 ~ 2022年3月(完全植入神经网络,让上下游企业可以以最低的成本运营整体的业务)
- V 3.1.0 -- 2022年3月 ~ 2022年6月(区域仓库业务布局,通过深度学习,实现多仓运营,成本最低化)
---
## 开发环境:
- Python 版本为 V 3.8.0 +
- Django 版本为 V 3.1.0 +(该版本Django才原生支持异步实时通信)
- Django-rest-framework 版本为 V 3.12.2 + (更高版本的Django-rest-Framework对Django3的兼容比较好)
- Django-silk 版本为 V 4.1.0 (如果是部署上线,请关闭silk,silk仅为调试API接口速度用,有可能会泄露用户信息)
- Quasar 版本为 V1.7.2 + (可以查看Quasar官网,来编辑GreaterWMS前端代码:[Quasar官网](http://www.quasarchs.com/))
- Vue 版本为 V 2.6.0 +(尽量不要使用Vue3,因为开发环境没有使用Vue3,不知道会出现什么问题)
- API,遵循 RESTful 架构
---
## 构建命令:
- 下载代码:
~~~shell
git clone https://github.com/Singosgu/GreaterWMS.git
~~~
- 安装Python库:
~~~python
pip install -r requirements.txt
~~~
注意:`安装需要Twisted库,这个库有时候会安装不上,需要下载下来本地安装`
- 下载地址:[TWISTED](https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted)
~~~python
pip install Twisted{你下载下来的版本名称}
~~~
注意:`本地安装需要注意路径`
- 初始化数据库:
~~~python
python manage.py makemigrations
~~~
- 迁移数据库:
~~~python
python manage.py migrate
~~~
创建数据库,Django默认使用sqlite3作为数据库,如果需要mysql数据库,请在greaterwms/settings.py里面配置DATABASE
### 开发服务器运行:
- 开发运行:
~~~python
daphne -p 8008 greaterwms.asgi:application
~~~
### 生产服务器运行:
- supervisor守护进程:
~~~shell
pip install supervisor
~~~
使用supervisor来守护Django进程,再使用Nginx做反向代理,至于superevisor的教程有很多,这里不做讲解
- Nginx支持:
推荐使用Nginx进行部署,部署的时候需要指定WebSocket链接,如果不指定,实时通信功能将报错
另需要修改从2.0.19版本以后,优化了请求地址修改方式,直接修改templates/dist/spa/statics/baseurl.js,中的baseurl和wsurl,就可以成功更改前端请求地址,不再需要做下面的quasar build打包工作。
如果需要修改前端内容,则还需要修改templates/public/statics/baseurl.js中的baseurl和wsurl,然后重新使用quasar build进行打包里的ws_url
~~~shell
## 示例更改前
const baseurl = 'http://127.0.0.1:8008/'
const wsurl = 'ws://127.0.0.1:8008/'
## 示例更改后
const baseurl = 'https://你的域名/'
const wsurl = 'wss://你的域名/websocket/'
~~~
如果服务器启用了SSL,请使用https和wss,如果没有启用SSL,则使用http和ws
修改后需要重新build前端代码
---
## 开发扩展:
因为使用的前后端分离的设计,所以可以通过API,开发更多的软件应用
### 物流智能AGV
- AGV的项目也已经开源,由于场地受限,仅实现智能发货,定点回库,使用的循迹感应器,超声波避障感应器,红外避障感应器,所有的指令通过网络传输,AGV绑定MAC地址和IP地址,保证了安全性,前提是,你需要有一个树莓派。
### 进销存
- 可以直接当一个进销存系统使用,简化仓库库位设置等操作即可。
### APP和小程序
- Quasar原生可以直接打包成IOS APP和Android APP
- 小程序的开发可以通过API开做二次开发,但小程序不支持put请求,所以需要自己再写一个请求接口。
- API的组合可以达到100万种,这样我们可以根据查询请求,来获得实时报表和数据监控
### 供应链管理系统
- 产品的数量,创建时间,最后使用时间是各方面统计的,所以可以方便采购计划和调拨计划进行库存的分析
- V 2.3.0及其以后的版本,将自带深度学习分析,所以可以直接使用分析结果作为供应链管理系统工具使用
### 多仓管理
- OPENID为用户的数据唯一标识,数据组统一标识为APPID,所以很方便可以实现多仓管理
### 波次拣货,发货
- 可以设置固定时间向服务器发出请求,从而达到波次拣货的功能
- 也可以直接使用任务工作,通过API查询分析结果来实现,推荐使用[APScheduler](https://pypi.org/project/APScheduler/)
~~~python
pip install apscheduler
~~~
### Milk-Run
- V 2.2.0及其以上版本,将原生支持此功能
- 如果现在就需要这个业务,可以根据API调用库存消耗,来实现此功能
### VMI
- V 2.1.0及其以上版本,将原生支持此功能
- 如果现在就需要这个业务,可以根据API调用库存消耗,来实现此功能
### 拣货路线优化
- 现在的拣货路线是按照库位排序
- V 2.3.0以后版本将原生支持此功能
- 如果现在需要这个业务,可以根据每天的拣货明细,调用API来实现此功能
---
## 开发指南:
### baseurl
- 是发起请求的基本网址,如果是本地调试,则默认为http://127.0.0.1:8008/ ,如果部署在服务器,则需要将其改为你的网站访问url
- 修改方式为,修改axios_request.js,注意`websocket的修改之前已经提到了`
### Django-silk
- django-silk为开发时的调试工具,可以统计每个接口的响应速度,如果需要部署到生产环境,请删除Django-silk相关配置,因为会有泄露用户信息的风险,或者直接修改Django-silk库,让用户只能看到自己的请求数据
### 数据库存储
- 数据库设计时考虑到数据迁移等问题,所以只有users里面的user_id和Django自带的user_id做了外键,其余所有字段全部没有使用外键,方便数据备份和数据库迁移
- 数据库是4段式设计
1. 验证数据用户归属
2. 验证数据安全性
3. 验证数据是否可以存入数据库
4. 存入数据库,并返回Response
### 关于数据传输
- 需要在所有的请求头headers里面加入token值,这个值就是用户的数据唯一标识OPENID
- 所有的数据传输需要设定content-type为application/json
### OPENID
- OPENID是注册用户数据的唯一标识,当管理员直接注册时,会有developer=1这个管理员标识。
- 你可以根据developer标识来做自定义二次开发
### APPID
- APPID是用户数据组唯一标识
- 如果需要多公司运营,或者多仓运营,可以通过APPID做统一链接,来实现多公司,多仓操作
### 用户权限
- 未对用户权限做过多限制,请根据自身的业务需要,做二次开发限制
---
## 业务流程:
### 管理员
- 点击注册,可以注册成为管理员账号,从而实现初始化程序设置
- 注册后会得到2个ID和1个开发者标识,OPENID是用户数据组唯一标识,通过OPENID绑定此OPENID下所有的数据,APPID是用户组数据唯一标识,通过APPID来实现多公司,多仓库功能,Developer标识是个布尔值,True代表这是个管理员账号
- 用户登入分2种:
1. 使用OPENID和员工名称直接登入
2. 管理员使用账号和密码登入
- 登入后前端会存储登入信息
- 可以通过查看我的OPENID来查看用户数据组的OPENID
- 如果需要多公司,多仓库操作,注意需要更改OPENID
- 更多管理员权限,请自行开发
### 员工管理
- 注册管理员后,新建一个员工
- 员工有2个字段,Staff_name(用于员工登入),Staff_type(员工类型来控制员工的权限)
- 系统没有对员工权限做任何限制,如果需要员工权限,请根据企业业务模型,自行修改Templates
- 点击Edit,可以修改员工信息
- 点击Delete,可以删除员工信息,系统后台会将Is_delete调成True
- 点击Contact
1. 可以直接和员工实时聊天,但是不可以和自己聊天
2. 可以新建一个备忘录员工,这样做其实是当成备忘录使用
3. 在个人中心,可以查看最近的联系人
4. Message标识会提醒你现在有多少未读消息
### 司机管理
- 司机管理只会在发货流程中用到
- 你需要知道货物是哪个司机提货取走的
### 仓库设置
- Warehouse
1. 仓库的创建只可以创建一个仓库,现在可以创建多个,但是只有第一个会起作用
2. 如果需要多仓处理,可以通过APPID进行二次开发,也可以直接重新创建一个管理员账号
3. 仓库的城市一定要填写,这是用来计算运费的
- Bin_Property
1. 库位属性决定了仓库中货物属于什么属性的货物
2. 4种属性:破损(Damage),锁定(Holding),质检(Inspection),正常(Normal
3. Beta版中,属性可以修改和删除,正式版将无法删除和修改
4. 所有的发货,都只会匹配Normal库位的货物
5. 收货上架和移库,都会根据库位属性,直接修改库存数量,仓库的库存数量不会出现负数
- Bin_Size
1. 库位的尺寸是帮助操作人员查看货物是否可以放入库位
2. 现行的版本没有对上架和移库尺寸做检查,将来会加入自动检查
- Bin_Set
1. 库位设置是必须的,通常库位设置是横纵横纵,比如A010101,即A横01纵01横01纵
2. 库位的设置需要设置库位属性和尺寸,属性很重要,他决定了此库位的货物是否为正常货物
### 基础设置
- Company
1. 公司基本信息的创建只可以创建一个公司,现在可以创建多个,但是只有第一个会起作用
2. 如果需要多公司处理,可以通过APPID进行二次开发,也可以直接重新创建一个管理员账号
3. 公司的城市一定要填写,这是用来显示在收发货单上的
- Supplier
1. 供应商的基础信息
2. 供应商的城市一定要填写,这是用来显示在收货单上的,并且也是要自动计算运费的
- Customer
1. 客户的基础信息
2. 客户的城市一定要填写,这是用来显示在发货单上的,并且也是要自动计算运费的
### 商品管理
- Unit
1. 商品的单位,系统会初始化创建一些,但可以自己添加和修改
- Class
1. 商品的类型,可以自己添加和修改
- Color
1. 商品的颜色,系统会初始化创建一些,但可以自己添加和修改
- Brand
1. 商品的品牌,可以自己添加和修改
- Shape
1. 商品的形状,系统会初始化创建一些,但可以自己添加和修改
- Specs
1. 商品的规格,可以自己添加和修改
- Origin
1. 商品的产地,可以自己添加和修改
- Goods List
1. 商品的列表
### 固定资产
- Capital
1. 固定资产创建,没有做过多拓展,只是记录使用
2. 可以统计托盘账目等
### 库存管理
- Stock List
1. 在库的货物总的库存数据量
2. Onhand_stock现有的库存数量
3. Can Order,可以用于下单发货的库存数量,因为有些货物已经被下了订单,虽然有现有库存,但是不可以再被订货
4. Ordered Stock,已经被下单的货物数量
5. ASN Stock,已经下了到货通知书,但还没有确认到货通知书的货物数量
6. DN Stock,已被下单,但是还没有确认订单数量
7. Pre Load,预计到货货物数量
8. Pre Sort,已经到货,卸货完成,等待分拣的货物数量
9. Sorted Stock,货物分拣完成,等待上架的货物数量
10. Pick Stock,发货单生成了拣货单,等待拣货的货物数量
11. Picked Stock,已经拣货完成,等待和司机交接的货物数量
12. Back Order Stock,欠货订单数量
- Bin Stock
1. Total Stock,这个库位该产品的所有库存数量
2. Pick Stock,这个库位需要拣货的数量
3. Picked Stock,这个库位拣货完成的数量
4. Move To Bin, 移库,移库后,会根据库位属性,直接更新库存数量,如果库位全部移空,则该库位会更新为空库位
- Empty Bin
1. 空库位明细
- Occupied Bin
1. 非空库位明细
### 收货管理
- ASN到货通知书状态
1. ASN Status = 1, ASN到货通知书创建完成,状态1是唯一可以删除和修改ASN信息的状态,他会显示在Pre Delivery中,即有了到货通知书,但是还没有到货,点击Confirm Delivery,即确认货物已经到达,ASN Status更新到2,此时已经无法再修改ASN信息
2. ASN Status = 2, 拓展开发为司机到货排队,如果我们有很多司机到货,这可以做成一个排队系统,同时也可以让采购和销售看到到货信息,减少不必要的邮件和电话沟通,点击Finish Loading,即确认货物已经卸货完成,ASN Status更新到3,货物信息会出现在Sorting,此时的ASN状态表示,货物已卸到仓库,等待分拣
3. ASN Status = 3, 货物分拣是必须的一个流程,没有货物分拣,货物是无法上架的,上架的原则就是货物整理好,摆放到相对应的库位上,点击Confirm SortedASN Status更新到4,即确认分拣完成,等待上架
4. 此时移动Sorted页面,会出现需要上架的货物明细,点击Move To Bin,上架完成,当然,系统会根据上架后的库位属性,自动更新商品库存数量信息
### 发货管理
- DN发货单状态
1. DN Status = 1, DN发货单创建完成,此时订单还是可以修改状态,且系统中的库存数量不会发生任何改变,点击Confirm OrderDN Status更新到2,即订单已经被确认,且无法更改,同时系统中的货物库存数量会自动更新,比如Can Order数量和Ordered数量
2. DN Status = 2, 这是订单被确认等待生成拣货单的过程,你可以点击单条订单Order Release来生成一个订单的拣货单,你也可以点击Release All Order,来将所有订单生成拣货单,如果是所有订单Release,那么会根据时间的先后进行库存匹配,库存不足时,会生成Back Order,即欠货订单,在这个过程中,DN单号是会发生改变的,如一家客户的多张订单,会被统一到一张订单中进行拣货,如客户订单无法满足,会将未满足部分生成欠货订单,欠货订单如果仍未得到匹配库存满足,将不再生成新的订单,DN Status会更新到3,即等待拣货的过程,已确认的订单和欠货订单都时Status为2的状态
3. DN Status = 3, 直接拣货,此功能会出现在Beta5更新
4. DN Status = 4, 发货交接,此功能会出现在Beta6更新
5. DN Status = 5, 客户签收,此功能会出现在Beta7更新
6. DN Status = 6, 对账结束,订单关闭,此功能会出现在Beta7更新
### 退货管理
- RO退货订单
此功能将会出现在正式版中
### 运费管理
- Transportation Fee
API已经完成,前端暂未更新入口,如果想要使用,可以直接调用Payment下的Transportation Fee API进行使用,运费自动计算模块已经做进收发货流程中
### 界面截图
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/inbound.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/outbound.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/stock.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/finace.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/goods.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/baseinfo.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/warehouse.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/staff.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/driver.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/api.png?raw=true"/></div></p>
<p><div align=center><img width="100%" height="100%" src="https://github.com/Singosgu/picfile/blob/master/CN/chat.png?raw=true"/></div></p>
<p><div align=center><img src="https://github.com/Singosgu/picfile/blob/master/CN/app1.png?raw=true"/></div></p>
<p><div align=center><img src="https://github.com/Singosgu/picfile/blob/master/CN/app2.png?raw=true"/></div></p>
<p><div align=center><img src="https://github.com/Singosgu/picfile/blob/master/CN/app3.png?raw=true"/></div></p>
<p><div align=center><img src="https://github.com/Singosgu/picfile/blob/master/CN/app4.png?raw=true"/></div></p>
@@ -1 +0,0 @@
7617270580ae099de75afba1ee0dfaf912f22a6d
-65
View File
@@ -1,65 +0,0 @@
~~~shell
sudo apt update
sudo apt upgrade
sudo apt install vim-gtk // 安装 vim
cd ~ // 到达Home目录
vi .bashrc // 把 "alias vi=vim" 加进 bashrc
source .bashrc // 刷新生效bashrc
sudo apt install git // 安装 git
sudo git clone https://github.com/Singosgu/GreaterWMS.git // 下载 GreaterWMS 从 github
sudo apt install nodejs // 安装 nodejs
sudo apt install npm // 安装 npm
sudo npm install n -g // 安装 n
sudo n stable // 下载 nodejs 的稳定版本
// 你需要确定你的nodejs是12或者14版本,Quasar只支持12或者14版本
// 这步完成以后,你需要重新启动你的Terminal,要不然升级不生效
sudo npm install npm -g // 升级 NPM 到最新版本
sudo npm install yarn -g // 安装 yarn
sudo npm install -g @quasar/cli // 安装 quasar/cli
quasar -v // 检查 Quasar 版本
python3 // 确定你的python版本是3.8以上版本,原则上3.6也是可以的,但是安装库会有些问题
pip3 list // 确定你是否安装有 pip3
sudo apt install python3-pip // 如果你没有pip3 ,就安装一下
pip3 list // 检查下是否安装成功
sudo chmod -R 755 GreaterWMS // 提权 GreaterWMS 文件夹
cd GreaterWMS // 进入GreaterWMS文件夹
sudo pip3 install -r requirements.txt
// 有些时候,你安装这些库会出问题,是因为python3版本的问题,不用担心,sudo pip3 install 出错的库就可以了.
sudo daphne -p 8008 greaterwms.asgi:application
// 现在打开浏览器,输入"127.0.0.1:8008",你会看到500错误,恭喜你,你已经可以正常部署接下来的事情了
Ctrl + C // 回到GreaterWMS文件夹
sudo python3 manage.py makemigrations // 数据库生成
sudo python3 manage.py migrate // 数据库迁移
sudo daphne -p 8008 greaterwms.asgi:application
// 现在打开浏览器,输入"127.0.0.1:8008",你会看到项目已经运行了
// 输入 "127.0.0.1:8008/myip", 你会得到你的内网IP,一定记住它
Ctrl + C // 回到GreaterWMS文件夹
cd templates //进入 templates 文件夹
从2.0.19版本以后,优化了请求地址修改方式,直接修改templates/dist/spa/statics/baseurl.js,中的baseurl和wsurl,就可以成功更改前端请求地址,不再需要做下面的quasar build打包工作。
如果需要修改前端内容,则还需要修改templates/public/statics/baseurl.js中的baseurl和wsurl,然后重新使用quasar build进行打包
sudo yarn config set registry https://registry.npm.taobao.org/ //更改yarn为国内源
sudo yarn install // 等待Yarn安装完成,其实你也可以sudo npm install ,就是会慢一点
sudo quasar d // 使用quasar命令启动前端页面
// 前端会向 "127.0.0.1:8008"发请求, 在这里我们只是看下项目是不是可以运行
Ctrl + C // 退回到templates文件夹
cd src/boot // 进入在src/boot文件夹
sudo vim axios_request.js // 我们开始更改请求地址
// 更改 "127.0.0.1" 成你的内网IP, baseurl 是http请求地址 , ws 是 websocket请求地址
按下 Esc 然后输入 ":wq" 去保存修改
// 现在,你已经知道怎么部署和修改请求地址了
sudo quasar build // 需要对修改进行重新打包
cd .. // 回到GreaterWMS文件夹
sudo daphne -b 0.0.0.0 -p 8008 greaterwms.asgi:application
// 现在,打开浏览器,输入 "你的内网IP:8008",你可以看到项目已经运行了
谢天谢地!!!
顺便说一句
1. 你知道了怎么修改请求地址
2. 你也可以按你的喜好,去更改Port
3. 你更可以使用Nginx或者Apache,把项目发布到互联网上
~~~
-59
View File
@@ -1,59 +0,0 @@
~~~shell
sudo apt update
sudo apt upgrade
sudo apt install vim-gtk // install vim
cd ~ // Go to home follder
vi .bashrc // add "alias vi=vim" in bashrc
source .bashrc // refresh bashrc
sudo apt install git // install git
sudo git clone https://github.com/Singosgu/GreaterWMS.git // Download GreaterWMS from github
sudo apt install nodejs // install nodejs
sudo apt install npm // install npm
sudo npm install n -g // update n
sudo n stable // Download nodejs to stable version
// You must confirm your nodejs version is 14 or 12 , cause Quasar just support 12 or 14
// after this step , you should re-open your terminal
sudo npm install npm -g // update npm to latestest
sudo npm install yarn -g // install yarn
sudo npm install -g @quasar/cli // install quasar/cli
quasar -v // check quasar version
python3 // To check your python version is 3.8 above
pip3 list // To check whether you have pip3
sudo apt install python3-pip // if you don't have pip3 , install it
pip3 list // check again
sudo chmod -R 755 GreaterWMS // approve GreaterWMS chmod
cd GreaterWMS
sudo pip3 install -r requirements.txt
// Some times , you can not install some lib . Cause your python3 version . Don't worry, sudo pip3 install it is ok.
sudo daphne -p 8008 greaterwms.asgi:application
// Now, Open the brower and enter "127.0.0.1:8008", If you see 500 error . Congratuation, you success.
Ctrl + C // out to terminal
sudo python3 manage.py makemigrations // database create
sudo python3 manage.py migrate // database create
sudo daphne -p 8008 greaterwms.asgi:application
// Now, Open the brower and enter "127.0.0.1:8008". You can see our project run
// Now , Enter "127.0.0.1:8008/myip", you will get Intranet ip, recorde it
Ctrl + C // out to terminal
cd templates // Go to templates follder
sudo yarn install // Waiting for yarn install
sudo quasar d // run quasar web
// quasar web will send request to "127.0.0.1:8008", this step just to check whether it can be run
Ctrl + C // out to terminal
cd src/boot // go to boot follder
sudo vim axios_request.js // go to this file to change the request link
// change "127.0.0.1" to your Intranet ip , baseurl is for http , ws is for websocket
Esc then enter ":wq" to save the change
// till now you know how to build it and change the request
sudo quasar build // Re-Build the Quasar Web
cd .. // back to greaterwms follder
sudo daphne -b 0.0.0.0 -p 8008 greaterwms.asgi:application
// Now, Open the brower and enter "your Intranet ip:8008". You can see our project run
Congratuation!!!
By The Way
1. You Know how to change the request
2. You also can change the port which you like
3. You can use Nginx or Apache to run the project on internet
~~~
-1
View File
@@ -1 +0,0 @@
d845ab52a97e28ec0282b25020c1284479f920f3
-105
View File
@@ -1,105 +0,0 @@
~~~shell
# 下载python3.9.2(版本以自己电脑系统为主,我们以64位为例)
https://www.python.org/ftp/python/3.9.2/python-3.9.2-amd64.exe
# 右键,以管理员运行exe文件,安装python3.9.2
# 注意一定要勾选上Add Python3.9 To PATH,然后点选Install Now
# 下载sqlite3(版本以自己电脑系统为主,我们以64位为例)
https://www.sqlite.org/2021/sqlite-dll-win64-x64-3350500.zip
# 解压zip文件,将解压出来的文件,覆盖python路径dll中的文件,地址为
~ C:\Users\{你的用户名}\AppData\Local\Programs\Python\Python39\DLLs
# 下载Node.JS14.16.1(版本以自己电脑系统为主,我们以64位为例)
https://nodejs.org/dist/v14.16.1/node-v14.16.1-x64.msi
# 安装Node.JS的时候,一定不要勾选Automatically,一直下一步,知道安装完成
# 下载Git(版本以自己电脑系统为主,我们以64位为例,需要下载setup版本)
https://git-scm.com/download/win
# 右键,以管理员运行exe文件,然后一直下一步就可以了
# 选择好你要把GreaterWMS摆在哪个目录中,右键,选择Git Bash Here
# 下载 GreaterWMS 从 github,由于网络原因,会很慢,多试几次
git clone https://github.com/Singosgu/GreaterWMS.git
# 左下角搜索栏,输入cmd
# 右键,以管理员运行cmd
# 查看Python版本
python -V
# 查看pip有没有装好
pip list
# 升级pip到最新版本
pip install --upgrade pip
# 进入GreaterWMS摆放目录,演示时摆在downlowad里面的,所以我们进去目录
~ cd C:\Users\{你的用户名}\Downloads\GreaterWMS\
# pip安装python依赖库
pip install -r requirements.txt
# Twisted可能安装不上,需要下载下来手动安装
https://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
# 下载自己适合的版本,比如:我的演示视频是Python3.9.2Win10版本是64位的
# 所以我就要下载Twisted-20.3.0-cp39-cp39-win_amd64.whl
# 将下载下来的Twisted摆在GreaterWMS根目录,手动安装
pip install Twisted-20.3.0-cp39-cp39-win_amd64.whl
# 再次运行安装requirements.txt
pip install -r requirements.txt
# 启动GreaterWMS
daphne -p 8008 greaterwms.asgi:application
# 这时候打开浏览器,输入127.0.0.1:8008
# 如果看到500报错,就说明之前的Python依赖已经全部安装完成了
# 回到CMD界面,按住Ctrl+C来退出项目启动
# 生成数据库迁移文件
python manage.py makemigrations
# 生成数据库
python manage.py migrate
# 再次启动项目
daphne -p 8008 greaterwms.asgi:application
# 这时候打开浏览器,输入127.0.0.1:8008
# 查看局域网IP,浏览器输入127.0.0.1:8008/myip
# 保存或者记住这个IP地址
# 一定注意,windows每次启动获得的内网IP是不同的,要么你路由器设置固定内网IP给这台电脑,要么你就不要关电脑
# 回到CMD界面,按住Ctrl+C来退出项目启动
# 进入templates目录
cd templates
从2.0.19版本以后,优化了请求地址修改方式,直接修改templates/dist/spa/statics/baseurl.js,中的baseurl和wsurl,就可以成功更改前端请求地址,不再需要做下面的quasar build打包工作。
如果需要修改前端内容,则还需要修改templates/public/statics/baseurl.js中的baseurl和wsurl,然后重新使用quasar build进行打包
# 升级下npm
npm install -g npm
# 切换npm源为国内源
npm config set registry https://registry.npm.taobao.org
# 安装Yarn
npm install -g yarn
# 更改yarn为国内源
yarn config set registry https://registry.npm.taobao.org/
# 安装quasar环境
npm install -g @quasar/cli
# 安装windows构建工具
#注意:如果安装不上请下载 Visual Studio 安装C++环境
npm install -g windows-build-tools
# 安装core-js依赖
npm install -g core-js
# 查看全局依赖是否安装完成
npm list -g --depth=0
# 安装项目依赖
yarn install
# 这个过程会有点慢,有时候会很快,是因为网络原因
# 如果发生报错,那是因为网络原因无法安装,多试几次就可以了,直到没有报错
# 进入发请求的文件,修改请求地址
~ 记事本编辑 GreaterWMS/templates/src/boot/axios_request
# 将127.0.0.1更改为你刚才查看到的内网IP
const baseurl = 'http://127.0.0.1:8008/'
const wsurl = 'ws://127.0.0.1:8008/'
# 保存退出
# templates目录下重新编译前端
quasar build
# 回到GreaterWMS根目录
cd ..
# 启动项目加入-b 0.0.0.0参数
daphne -b 0.0.0.0 -p 8008 greaterwms.asgi:application
# 接下来就可以使用你的浏览器,访问{ http://内网IP:8008 }来查看该项目了
# 局域网上的电脑也可以通过这个IP来访问项目
谢天谢地!!!
顺便说一句
1. 你知道了怎么修改请求地址
2. 你也可以按你的喜好,去更改Port
3. 你更可以使用Nginx或者Apache,把项目发布到互联网上
~~~
-1
View File
@@ -1 +0,0 @@
63e42d89d6750efd58197b6b61d732d9f309ffd2
@@ -1 +0,0 @@
8b42c0ea8087964023ae7aa09fae24b32cc62b14
View File
-5
View File
@@ -1,5 +0,0 @@
from django.contrib import admin
from . models import AsnListModel, AsnDetailModel
admin.site.register(AsnListModel)
admin.site.register(AsnDetailModel)
-5
View File
@@ -1,5 +0,0 @@
from django.apps import AppConfig
class AsnConfig(AppConfig):
name = 'asn'
-116
View File
@@ -1,116 +0,0 @@
from rest_framework_csv.renderers import CSVStreamingRenderer
def list_file_headers():
return [
'asn_code',
'asn_status',
'total_weight',
'total_volume',
'total_cost',
'supplier',
'creater',
'create_time',
'update_time'
]
def list_cn_data_header():
return dict([
('asn_code', u'ASN单号'),
('asn_status', u'ASN状态'),
('total_weight', u'总重量'),
('total_volume', u'总体积'),
('total_cost', u'总成本'),
('supplier', u'供应商'),
('creater', u'创建人'),
('create_time', u'创建时间'),
('update_time', u'更新时间')
])
def list_en_data_header():
return dict([
('asn_code', u'ASN Code'),
('asn_status', u'ASN Status'),
('total_weight', u'Total Weight'),
('total_volume', u'Total Volume'),
('total_cost', u'Total Cost'),
('supplier', u'Supplier'),
('creater', u'Creater'),
('create_time', u'Create Time'),
('update_time', u'Update Time')
])
def detail_file_headers():
return [
'asn_code',
'asn_status',
'supplier',
'goods_code',
'goods_qty',
'goods_actual_qty',
'sorted_qty',
'goods_shortage_qty',
'goods_more_qty',
'goods_damage_qty',
'goods_weight',
'goods_volume',
'goods_cost',
'creater',
'create_time',
'update_time'
]
def detail_cn_data_header():
return dict([
('asn_code', u'ASN单号'),
('asn_status', u'ASN状态'),
('supplier', u'供应商'),
('goods_code', u'商品编码'),
('goods_qty', u'订单数量'),
('goods_actual_qty', u'实际到货数量'),
('sorted_qty', u'已分拣数量'),
('goods_shortage_qty', u'少到货数量'),
('goods_more_qty', u'多到货数量'),
('goods_damage_qty', u'破损数量'),
('goods_weight', u'商品重量'),
('goods_volume', u'商品体积'),
('goods_cost', u'商品成本'),
('creater', u'创建人'),
('create_time', u'创建时间'),
('update_time', u'更新时间')
])
def detail_en_data_header():
return dict([
('asn_code', u'ASN Code'),
('asn_status', u'ASN Status'),
('supplier', u'Supplier'),
('goods_code', u'Goods Code'),
('goods_qty', u'Goods Qty'),
('goods_actual_qty', u'Goods Actual Qty'),
('sorted_qty', u'Sorted Qty'),
('goods_shortage_qty', u'Goods Shortage Qty'),
('goods_more_qty', u'Goods More Qty'),
('goods_damage_qty', u'Goods Damage Qty'),
('goods_weight', u'Goods Weight'),
('goods_volume', u'Goods Volume'),
('goods_cost', u'Goods Cost'),
('creater', u'Creater'),
('create_time', u'Create Time'),
('update_time', u'Update Time')
])
class FileListRenderCN(CSVStreamingRenderer):
header = list_file_headers()
labels = list_cn_data_header()
class FileListRenderEN(CSVStreamingRenderer):
header = list_file_headers()
labels = list_en_data_header()
class FileDetailRenderCN(CSVStreamingRenderer):
header = detail_file_headers()
labels = detail_cn_data_header()
class FileDetailRenderEN(CSVStreamingRenderer):
header = detail_file_headers()
labels = detail_en_data_header()
-43
View File
@@ -1,43 +0,0 @@
from django_filters import FilterSet
from .models import AsnListModel, AsnDetailModel
class AsnListFilter(FilterSet):
class Meta:
model = AsnListModel
fields = {
"id": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"asn_code": ['exact', 'iexact', 'contains', 'icontains'],
"asn_status": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"total_weight": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"total_volume": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"total_cost": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"supplier": ['exact', 'iexact', 'contains', 'icontains'],
"creater": ['exact', 'iexact', 'contains', 'icontains'],
"is_delete": ['exact', 'iexact'],
"create_time": ['exact', 'iexact', 'year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range'],
"update_time": ['exact', 'iexact', 'year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range']
}
class AsnDetailFilter(FilterSet):
class Meta:
model = AsnDetailModel
fields = {
"id": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"asn_code": ['exact', 'iexact', 'contains', 'icontains'],
"asn_status": ['exact', 'iexact'],
"supplier": ['exact', 'iexact', 'contains', 'icontains'],
"goods_code": ['exact', 'iexact', 'contains', 'icontains'],
"goods_qty": ['exact', 'iexact', 'gt', 'lt', 'gte', 'lte'],
"goods_actual_qty": ['exact', 'iexact', 'gt', 'lt', 'gte', 'lte'],
"sorted_qty": ['exact', 'iexact', 'gt', 'lt', 'gte', 'lte'],
"goods_shortage_qty": ['exact', 'iexact', 'gt', 'lt', 'gte', 'lte'],
"goods_more_qty": ['exact', 'iexact', 'gt', 'lt', 'gte', 'lte'],
"goods_damage_qty": ['exact', 'iexact', 'gt', 'lt', 'gte', 'lte'],
"goods_weight": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"goods_volume": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"goods_cost": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"creater": ['exact', 'iexact', 'contains', 'icontains'],
"is_delete": ['exact', 'iexact'],
"create_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range'],
"update_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range']
}
View File
-55
View File
@@ -1,55 +0,0 @@
from django.db import models
class AsnListModel(models.Model):
asn_code = models.CharField(max_length=255, verbose_name="ASN Code")
asn_status = models.BigIntegerField(default=1, verbose_name="ASN Status")
total_weight = models.FloatField(default=0, verbose_name="Total Weight")
total_volume = models.FloatField(default=0, verbose_name="Total Volume")
total_cost = models.FloatField(default=0, verbose_name="Total Cost")
supplier = models.CharField(max_length=255, verbose_name="ASN Supplier")
creater = models.CharField(max_length=255, verbose_name="Who Created")
bar_code = models.CharField(max_length=255, verbose_name="Bar Code")
openid = models.CharField(max_length=255, verbose_name="Openid")
transportation_fee = models.JSONField(default=dict, verbose_name="Transportation Fee")
is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
class Meta:
db_table = 'asnlist'
verbose_name = 'data id'
verbose_name_plural = "data id"
ordering = ['-id']
def __str__(self):
return self.pk
class AsnDetailModel(models.Model):
asn_code = models.CharField(max_length=255, verbose_name="ASN Code")
asn_status = models.BigIntegerField(default=1, verbose_name="ASN Status")
supplier = models.CharField(max_length=255, verbose_name="ASN Supplier")
goods_code = models.CharField(max_length=255, verbose_name="Goods Code")
goods_qty = models.BigIntegerField(default=0, verbose_name="Goods QTY")
goods_actual_qty = models.BigIntegerField(default=0, verbose_name="Goods Actual QTY")
sorted_qty = models.BigIntegerField(default=0, verbose_name="Sorted QTY")
goods_shortage_qty = models.BigIntegerField(default=0, verbose_name="Goods Shortage QTY")
goods_more_qty = models.BigIntegerField(default=0, verbose_name="Goods More QTY")
goods_damage_qty = models.BigIntegerField(default=0, verbose_name="Goods damage QTY")
goods_weight = models.FloatField(default=0, verbose_name="Goods Weight")
goods_volume = models.FloatField(default=0, verbose_name="Goods Volume")
goods_cost = models.FloatField(default=0, verbose_name="Goods Cost")
creater = models.CharField(max_length=255, verbose_name="Who Created")
openid = models.CharField(max_length=255, verbose_name="Openid")
is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
class Meta:
db_table = 'asndetail'
verbose_name = 'data id'
verbose_name_plural = "data id"
ordering = ['-id']
def __str__(self):
return self.pk
-63
View File
@@ -1,63 +0,0 @@
from collections import OrderedDict
from rest_framework.exceptions import APIException
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.utils.urls import replace_query_param, remove_query_param
from supplier.models import ListModel as supplier
class MyPageNumberPaginationASNList(PageNumberPagination):
page_size = 30
page_size_query_param = "max_page"
max_page_size = 1000
page_query_param = 'page'
def get_previous_link(self):
if not self.page.has_previous():
return None
url = self.request.build_absolute_uri()
page_number = self.page.previous_page_number()
ssl_check = str(self.request.META.get('HTTP_ORIGIN')).split(':')[0]
url_combine = str(url).split(':')
if len(str(url).split(':')) == 2:
url = ssl_check + ':' + url_combine[1]
if page_number == 1:
return remove_query_param(url, self.page_query_param)
return replace_query_param(url, self.page_query_param, page_number)
elif len(str(url).split(':')) == 3:
url = ssl_check + ':' + url_combine[1] + ':' + url_combine[2]
if page_number == 1:
return remove_query_param(url, self.page_query_param)
return replace_query_param(url, self.page_query_param, page_number)
else:
raise APIException({"detail": "Wrong API Url"})
def get_next_link(self):
if not self.page.has_next():
return None
url = self.request.build_absolute_uri()
page_number = self.page.next_page_number()
ssl_check = str(self.request.META.get('HTTP_ORIGIN')).split(':')[0]
url_combine = str(url).split(':')
if len(str(url).split(':')) == 2:
url = ssl_check + ':' + url_combine[1]
return replace_query_param(url, self.page_query_param, page_number)
elif len(str(url).split(':')) == 3:
url = ssl_check + ':' + url_combine[1] + ':' + url_combine[2]
return replace_query_param(url, self.page_query_param, page_number)
else:
raise APIException({"detail": "Wrong API Url"})
def get_paginated_response(self, data):
supplier_list_data = supplier.objects.filter(openid=self.request.auth.openid, is_delete=False)
supplier_list = []
for i in range(len(supplier_list_data)):
supplier_list.append(supplier_list_data[i].supplier_name)
return Response(OrderedDict([
('supplier_list', supplier_list),
('count', self.page.paginator.count),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data)
]))
-156
View File
@@ -1,156 +0,0 @@
from rest_framework import serializers
from .models import AsnListModel, AsnDetailModel
from utils import datasolve
class ASNListGetSerializer(serializers.ModelSerializer):
asn_code = serializers.CharField(read_only=True, required=False)
asn_status = serializers.IntegerField(read_only=True, required=False)
supplier = serializers.CharField(read_only=True, required=False)
bar_code = serializers.CharField(read_only=True, required=False)
creater = serializers.CharField(read_only=True, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = AsnListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'openid', ]
class ASNListPostSerializer(serializers.ModelSerializer):
openid = serializers.CharField(read_only=False, required=False, validators=[datasolve.openid_validate])
asn_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.asn_data_validate])
supplier = serializers.CharField(read_only=False, required=False)
bar_code = serializers.CharField(read_only=False, required=True)
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = AsnListModel
exclude = ['is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class ASNListPartialUpdateSerializer(serializers.ModelSerializer):
asn_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.asn_data_validate])
class Meta:
model = AsnListModel
exclude = ['is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class ASNListUpdateSerializer(serializers.ModelSerializer):
asn_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.asn_data_validate])
class Meta:
model = AsnListModel
exclude = ['is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class ASNDetailGetSerializer(serializers.ModelSerializer):
asn_code = serializers.CharField(read_only=True, required=False)
supplier = serializers.CharField(read_only=True, required=False)
goods_code = serializers.CharField(read_only=True, required=False)
goods_qty = serializers.IntegerField(read_only=True, required=False)
goods_actual_qty = serializers.IntegerField(read_only=True, required=False)
sorted_qty = serializers.IntegerField(read_only=True, required=False)
goods_shortage_qty = serializers.IntegerField(read_only=True, required=False)
goods_more_qty = serializers.IntegerField(read_only=True, required=False)
goods_damage_qty = serializers.IntegerField(read_only=True, required=False)
creater = serializers.CharField(read_only=True, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = AsnDetailModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'openid']
class ASNDetailPostSerializer(serializers.ModelSerializer):
openid = serializers.CharField(read_only=False, required=False, validators=[datasolve.openid_validate])
asn_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
supplier = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
goods_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
goods_qty = serializers.IntegerField(read_only=False, required=True, validators=[datasolve.qty_0_data_validate])
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = AsnDetailModel
exclude = ['is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class ASNSortedPostSerializer(serializers.ModelSerializer):
openid = serializers.CharField(read_only=False, required=False, validators=[datasolve.openid_validate])
asn_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
supplier = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
goods_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
goods_qty = serializers.IntegerField(read_only=False, required=True, validators=[datasolve.qty_data_validate])
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = AsnDetailModel
exclude = ['is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class ASNDetailUpdateSerializer(serializers.ModelSerializer):
asn_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
supplier = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
goods_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
goods_qty = serializers.IntegerField(read_only=False, required=True, validators=[datasolve.qty_0_data_validate])
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = AsnDetailModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class ASNDetailPartialUpdateSerializer(serializers.ModelSerializer):
asn_code = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
supplier = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
goods_code = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
goods_qty = serializers.IntegerField(read_only=False, required=False, validators=[datasolve.qty_0_data_validate])
creater = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
class Meta:
model = AsnDetailModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class MoveToBinSerializer(serializers.ModelSerializer):
bin_name = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
qty = serializers.IntegerField(read_only=False, required=True, validators=[datasolve.qty_0_data_validate])
class Meta:
model = AsnDetailModel
ref_name = 'AsnMoveToBin'
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class FileListRenderSerializer(serializers.ModelSerializer):
asn_code = serializers.CharField(read_only=False, required=False)
asn_status = serializers.IntegerField(read_only=False, required=False)
total_weight = serializers.FloatField(read_only=False, required=False)
total_volume = serializers.FloatField(read_only=False, required=False)
total_cost = serializers.FloatField(read_only=False, required=False)
supplier = serializers.CharField(read_only=False, required=False)
creater = serializers.CharField(read_only=False, required=False)
transportation_fee = serializers.JSONField(read_only=False, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = AsnListModel
ref_name = 'ASNFileListRenderSerializer'
exclude = ['openid', 'is_delete', ]
class FileDetailRenderSerializer(serializers.ModelSerializer):
asn_code = serializers.CharField(read_only=False, required=False)
asn_status = serializers.IntegerField(read_only=False, required=False)
goods_code = serializers.CharField(read_only=False, required=False)
goods_qty = serializers.IntegerField(read_only=False, required=False)
goods_actual_qty = serializers.IntegerField(read_only=False, required=False)
sorted_qty = serializers.IntegerField(read_only=False, required=False)
goods_shortage_qty = serializers.IntegerField(read_only=False, required=False)
goods_more_qty = serializers.IntegerField(read_only=False, required=False)
goods_damage_qty = serializers.IntegerField(read_only=False, required=False)
goods_weight = serializers.FloatField(read_only=False, required=False)
goods_volume = serializers.FloatField(read_only=False, required=False)
goods_cost = serializers.FloatField(read_only=False, required=False)
supplier = serializers.CharField(read_only=False, required=False)
creater = serializers.CharField(read_only=False, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = AsnDetailModel
ref_name = 'ASNFileDetailRenderSerializer'
exclude = ['openid', 'is_delete', ]
View File
-35
View File
@@ -1,35 +0,0 @@
from django.urls import path, re_path
from . import views
urlpatterns = [
path(r'list/', views.AsnListViewSet.as_view({"get": "list", "post": "create"}), name="asnlist"),
re_path(r'^list/(?P<pk>\d+)/$', views.AsnListViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
}), name="asnlist_1"),
path(r'detail/', views.AsnDetailViewSet.as_view({"get": "list", "post": "create", 'put': 'update'}), name="asndetail"),
re_path(r'^detail/(?P<pk>\d+)/$', views.AsnDetailViewSet.as_view({
'get': 'retrieve',
}), name="asndetail_1"),
re_path(r'^viewprint/(?P<pk>\d+)/$', views.AsnViewPrintViewSet.as_view({
'get': 'retrieve',
}), name="asnviewprint_1"),
re_path(r'^preload/(?P<pk>\d+)/$', views.AsnPreLoadViewSet.as_view({
'post': 'create',
}), name="preload_1"),
re_path(r'^presort/(?P<pk>\d+)/$', views.AsnPreSortViewSet.as_view({
'post': 'create',
}), name="presort_1"),
path(r'sorted/', views.AsnSortedViewSet.as_view({"put": "update"}), name="sorted"),
re_path(r'^sorted/(?P<pk>\d+)/$', views.AsnSortedViewSet.as_view({
'post': 'create'
}), name="sorted_1"),
path(r'movetobin/', views.MoveToBinViewSet.as_view({'put': 'update'}), name="movetobin"),
re_path(r'^movetobin/(?P<pk>\d+)/$', views.MoveToBinViewSet.as_view({
'post': 'create',
}), name="movetobin_1"),
path(r'filelist/', views.FileListDownloadView.as_view({"get": "list"}), name="asnfilelistdownload"),
path(r'filedetail/', views.FileDetailDownloadView.as_view({"get": "list"}), name="asnfiledetaildownload"),
]
-1188
View File
File diff suppressed because it is too large Load Diff
View File
-4
View File
@@ -1,4 +0,0 @@
from django.contrib import admin
from . models import ListModel
admin.site.register(ListModel)
-38
View File
@@ -1,38 +0,0 @@
from django.apps import AppConfig
from django.db.models.signals import post_migrate
class BinpropertyConfig(AppConfig):
name = 'binproperty'
def ready(self):
post_migrate.connect(do_init_data, sender=self)
def do_init_data(sender, **kwargs):
init_category()
def init_category():
"""
:return:None
"""
try:
from .models import ListModel as ls
if ls.objects.filter(openid__iexact='init_data').exists():
if ls.objects.filter(openid__iexact='init_data').count() != 4:
ls.objects.filter(openid__iexact='init_data').delete()
init_data = [
ls(id=1, openid='init_data', bin_property='Damage', creater='GreaterWMS'),
ls(id=2, openid='init_data', bin_property='Inspection', creater='GreaterWMS'),
ls(id=3, openid='init_data', bin_property='Normal', creater='GreaterWMS'),
ls(id=4, openid='init_data', bin_property='Holding', creater='GreaterWMS')
]
ls.objects.bulk_create(init_data, batch_size=100)
else:
init_data = [
ls(id=1, openid='init_data', bin_property='Damage', creater='GreaterWMS'),
ls(id=2, openid='init_data', bin_property='Inspection', creater='GreaterWMS'),
ls(id=3, openid='init_data', bin_property='Normal', creater='GreaterWMS'),
ls(id=4, openid='init_data', bin_property='Holding', creater='GreaterWMS')
]
ls.objects.bulk_create(init_data, batch_size=100)
except:
pass
-14
View File
@@ -1,14 +0,0 @@
from django_filters import FilterSet
from .models import ListModel
class Filter(FilterSet):
class Meta:
model = ListModel
fields = {
"id": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"bin_property": ['exact', 'iexact', 'contains', 'icontains'],
"creater": ['exact', 'iexact', 'contains', 'icontains'],
"is_delete": ['exact', 'iexact'],
"create_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range'],
"update_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range']
}
View File
-18
View File
@@ -1,18 +0,0 @@
from django.db import models
class ListModel(models.Model):
bin_property = models.CharField(max_length=32, verbose_name="Bin property")
creater = models.CharField(max_length=255, verbose_name="Who created")
openid = models.CharField(max_length=255, verbose_name="Openid")
is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
class Meta:
db_table = 'binproperty'
verbose_name = 'data id'
verbose_name_plural = "data id"
ordering = ['bin_property']
def __str__(self):
return self.pk
-14
View File
@@ -1,14 +0,0 @@
from rest_framework import serializers
from .models import ListModel
class BinpropertyGetSerializer(serializers.ModelSerializer):
bin_property = serializers.CharField(read_only=True, required=False)
creater = serializers.CharField(read_only=True, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = ListModel
ref_name = 'BinpropertyGetSerializer'
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', ]
View File
-6
View File
@@ -1,6 +0,0 @@
from django.urls import path
from . import views
urlpatterns = [
path(r'', views.APIViewSet.as_view({"get": "list"}), name="binproperty")
]
-29
View File
@@ -1,29 +0,0 @@
from rest_framework import viewsets
from .models import ListModel
from . import serializers
from utils.page import MyPageNumberPagination
from rest_framework.filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from .filter import Filter
class APIViewSet(viewsets.ModelViewSet):
"""
list:
Response a data listall
"""
pagination_class = MyPageNumberPagination
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
def get_queryset(self):
if self.request.user:
return ListModel.objects.filter(is_delete=False)
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list']:
return serializers.BinpropertyGetSerializer
else:
return self.http_method_not_allowed(request=self.request)
View File
-4
View File
@@ -1,4 +0,0 @@
from django.contrib import admin
from . models import ListModel
admin.site.register(ListModel)
-4
View File
@@ -1,4 +0,0 @@
from django.apps import AppConfig
class BinsetConfig(AppConfig):
name = 'binset'
-42
View File
@@ -1,42 +0,0 @@
from rest_framework_csv.renderers import CSVStreamingRenderer
def file_headers():
return [
'bin_name',
'bin_size',
'bin_property',
'empty_label',
'creater',
'create_time',
'update_time'
]
def cn_data_header():
return dict([
('bin_name', u'库位名称'),
('bin_size', u'库位尺寸'),
('bin_property', u'库位属性'),
('empty_label', u'空库位标识'),
('creater', u'创建人'),
('create_time', u'创建时间'),
('update_time', u'更新时间')
])
def en_data_header():
return dict([
('bin_name', u'Bin Name'),
('bin_size', u'Bin Size'),
('bin_property', u'Bin Property'),
('empty_label', u'Empty Label'),
('creater', u'Creater'),
('create_time', u'Create Time'),
('update_time', u'Update Time')
])
class FileRenderCN(CSVStreamingRenderer):
header = file_headers()
labels = cn_data_header()
class FileRenderEN(CSVStreamingRenderer):
header = file_headers()
labels = en_data_header()
-17
View File
@@ -1,17 +0,0 @@
from django_filters import FilterSet
from .models import ListModel
class Filter(FilterSet):
class Meta:
model = ListModel
fields = {
"id": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range', ],
"bin_name": ['exact', 'iexact', 'contains', 'icontains'],
"bin_size": ['exact', 'iexact', 'contains', 'icontains'],
"bin_property": ['exact', 'iexact', 'contains', 'icontains'],
"empty_label": ['exact', 'iexact'],
"creater": ['exact', 'iexact', 'contains', 'icontains'],
"is_delete": ['exact', 'iexact'],
"create_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range'],
"update_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range']
}
View File
-22
View File
@@ -1,22 +0,0 @@
from django.db import models
class ListModel(models.Model):
bin_name = models.CharField(max_length=255, verbose_name="Bin Name")
bin_size = models.CharField(max_length=255, verbose_name="Bin Size")
bin_property = models.CharField(max_length=11, verbose_name="Bin Property")
empty_label = models.BooleanField(default=True, verbose_name="Empty Label")
creater = models.CharField(max_length=255, verbose_name="Who Created")
bar_code = models.CharField(max_length=255, verbose_name="Bar Code")
openid = models.CharField(max_length=255, verbose_name="Openid")
is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
class Meta:
db_table = 'binset'
verbose_name = 'data id'
verbose_name_plural = "data id"
ordering = ['bin_name']
def __str__(self):
return self.pk
-70
View File
@@ -1,70 +0,0 @@
from collections import OrderedDict
from rest_framework.exceptions import APIException
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
from rest_framework.utils.urls import replace_query_param, remove_query_param
from binproperty.models import ListModel as binproperty
from binsize.models import ListModel as binsize
from django.db.models import Q
class MyPageNumberPagination(PageNumberPagination):
page_size = 30
page_size_query_param = "max_page"
max_page_size = 1000
page_query_param = 'page'
def get_previous_link(self):
if not self.page.has_previous():
return None
url = self.request.build_absolute_uri()
page_number = self.page.previous_page_number()
ssl_check = str(self.request.META.get('HTTP_ORIGIN')).split(':')[0]
url_combine = str(url).split(':')
if len(str(url).split(':')) == 2:
url = ssl_check + ':' + url_combine[1]
if page_number == 1:
return remove_query_param(url, self.page_query_param)
return replace_query_param(url, self.page_query_param, page_number)
elif len(str(url).split(':')) == 3:
url = ssl_check + ':' + url_combine[1] + ':' + url_combine[2]
if page_number == 1:
return remove_query_param(url, self.page_query_param)
return replace_query_param(url, self.page_query_param, page_number)
else:
raise APIException({"detail": "Wrong API Url"})
def get_next_link(self):
if not self.page.has_next():
return None
url = self.request.build_absolute_uri()
page_number = self.page.next_page_number()
ssl_check = str(self.request.META.get('HTTP_ORIGIN')).split(':')[0]
url_combine = str(url).split(':')
if len(str(url).split(':')) == 2:
url = ssl_check + ':' + url_combine[1]
return replace_query_param(url, self.page_query_param, page_number)
elif len(str(url).split(':')) == 3:
url = ssl_check + ':' + url_combine[1] + ':' + url_combine[2]
return replace_query_param(url, self.page_query_param, page_number)
else:
raise APIException({"detail": "Wrong API Url"})
def get_paginated_response(self, data):
bin_property_list_data = binproperty.objects.filter(Q(openid=self.request.auth.openid, is_delete=False) |
Q(openid='init_data', is_delete=False))
bin_property_list = []
for i in range(len(bin_property_list_data)):
bin_property_list.append(bin_property_list_data[i].bin_property)
bin_size_list_data = binsize.objects.filter(openid=self.request.auth.openid, is_delete=False)
bin_size_list = []
for i in range(len(bin_size_list_data)):
bin_size_list.append(bin_size_list_data[i].bin_size)
return Response(OrderedDict([
('bin_size_list', bin_size_list),
('bin_property_list', bin_property_list),
('count', self.page.paginator.count),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('results', data)
]))
-79
View File
@@ -1,79 +0,0 @@
from rest_framework import serializers
from .models import ListModel
from utils import datasolve
class ScannerBinsetTagGetSerializer(serializers.ModelSerializer):
bin_name = serializers.CharField(read_only=True, required=False)
bin_size = serializers.CharField(read_only=True, required=False)
bin_property = serializers.CharField(read_only=True, required=False)
empty_label = serializers.BooleanField(read_only=True, required=False)
creater = serializers.CharField(read_only=True, required=False)
bar_code = serializers.CharField(read_only=True, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', ]
class BinsetGetSerializer(serializers.ModelSerializer):
bin_name = serializers.CharField(read_only=True, required=False)
bin_size = serializers.CharField(read_only=True, required=False)
bin_property = serializers.CharField(read_only=True, required=False)
empty_label = serializers.BooleanField(read_only=True, required=False)
creater = serializers.CharField(read_only=True, required=False)
bar_code = serializers.CharField(read_only=True, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', ]
class BinsetPostSerializer(serializers.ModelSerializer):
openid = serializers.CharField(read_only=False, required=False, validators=[datasolve.openid_validate])
bin_name = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
bin_size = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
bin_property = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
bar_code = serializers.CharField(read_only=False, required=True)
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class BinsetUpdateSerializer(serializers.ModelSerializer):
bin_name = serializers.CharField(read_only=True, required=False)
bin_size = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
bin_property = serializers.CharField(read_only=True, required=False)
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
bar_code = serializers.CharField(read_only=False, required=False)
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class BinsetPartialUpdateSerializer(serializers.ModelSerializer):
bin_name = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
bin_size = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
bin_property = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
creater = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class FileRenderSerializer(serializers.ModelSerializer):
bin_name = serializers.CharField(read_only=False, required=False)
bin_size = serializers.CharField(read_only=False, required=False)
bin_property = serializers.CharField(read_only=False, required=False)
empty_label = serializers.BooleanField(read_only=False, required=False)
creater = serializers.CharField(read_only=False, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = ListModel
ref_name = 'BinSetFileRenderSerializer'
exclude = ['openid', 'is_delete', ]
View File
-14
View File
@@ -1,14 +0,0 @@
from django.urls import path, re_path
from . import views
urlpatterns = [
path(r'', views.APIViewSet.as_view({"get": "list", "post": "create"}), name="binset"),
path(r'file/', views.FileDownloadView.as_view({"get": "list"}), name="binsetfiledownload"),
re_path(r'^(?P<pk>\d+)/$', views.APIViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
}), name="binset_1"),
path(r'scannerbintag/<str:bar_code>/',views.ScannerBinsetTagView.as_view({"get":"retrieve"}))
]
-236
View File
@@ -1,236 +0,0 @@
from rest_framework import viewsets
from .models import ListModel
from . import serializers
from .page import MyPageNumberPagination
from rest_framework.filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.response import Response
from .filter import Filter
from rest_framework.exceptions import APIException
from django.db.models import Q
from binsize.models import ListModel as binsize
from scanner.models import ListModel as scanner
from binproperty.models import ListModel as binproperty
from .serializers import FileRenderSerializer
from django.http import StreamingHttpResponse
from .files import FileRenderCN, FileRenderEN
from rest_framework.settings import api_settings
from utils.md5 import Md5
from .serializers import ScannerBinsetTagGetSerializer
class ScannerBinsetTagView(viewsets.ModelViewSet):
"""
retrieve:
Response a data listget
http://127.0.0.1:8008/binset/scannerbintag/3d89ad23d185d5f206d860745c5c4121/
"""
pagination_class = MyPageNumberPagination
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
lookup_field = 'bar_code'
def get_project(self):
try:
bar_code = self.kwargs['bar_code']
return bar_code
except:
return None
def get_queryset(self):
bar_code = self.get_project()
if self.request.user:
if bar_code is None:
return ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False)
else:
return ListModel.objects.filter(openid=self.request.auth.openid, bar_code=bar_code, is_delete=False)
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list', 'retrieve', 'destroy']:
return serializers.ScannerBinsetTagGetSerializer
else:
return self.http_method_not_allowed(request=self.request)
class APIViewSet(viewsets.ModelViewSet):
"""
retrieve:
Response a data listget
list:
Response a data listall
create:
Create a data linepost
delete:
Delete a data linedelete)
partial_update:
Partial_update a datapatchpartial_update
update:
Update a dataputupdate
"""
pagination_class = MyPageNumberPagination
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
def get_project(self):
try:
id = self.kwargs.get('pk')
return id
except:
return None
def get_queryset(self):
id = self.get_project()
if self.request.user:
if id is None:
return ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False)
else:
return ListModel.objects.filter(openid=self.request.auth.openid, id=id, is_delete=False)
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list', 'retrieve', 'destroy']:
return serializers.BinsetGetSerializer
elif self.action in ['create']:
return serializers.BinsetPostSerializer
elif self.action in ['update']:
return serializers.BinsetUpdateSerializer
elif self.action in ['partial_update']:
return serializers.BinsetPartialUpdateSerializer
else:
return self.http_method_not_allowed(request=self.request)
def create(self, request, *args, **kwargs):
data = self.request.data
data['openid'] = self.request.auth.openid
if ListModel.objects.filter(openid=data['openid'], bin_name=data['bin_name'], is_delete=False).exists():
raise APIException({"detail": "Data exists"})
else:
if binsize.objects.filter(openid=data['openid'], bin_size=data['bin_size'], is_delete=False).exists():
if binproperty.objects.filter(Q(openid=data['openid'], bin_property=data['bin_property'], is_delete=False) |
Q(openid='init_data', bin_property=data['bin_property'], is_delete=False)).exists():
data['bar_code'] = Md5.md5(data['bin_name'])
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
scanner.objects.create(openid=self.request.auth.openid, mode="BINSET", code=data['bin_name'],
bar_code=data['bar_code'])
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
else:
raise APIException({"detail": "Bin property does not exists or it has been changed"})
else:
raise APIException({"detail": "Bin size does not exists or it has been changed"})
def update(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot update data which not yours"})
else:
data = self.request.data
if binsize.objects.filter(openid=self.request.auth.openid, bin_size=data['bin_size'], is_delete=False).exists():
if binproperty.objects.filter(Q(openid=self.request.auth.openid, bin_property=data['bin_property'], is_delete=False) |
Q(openid='init_data', bin_property=data['bin_property'], is_delete=False)).exists():
serializer = self.get_serializer(qs, data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
else:
raise APIException({"detail": "Bin property does not exists or it has been changed"})
else:
raise APIException({"detail": "Bin size does not exists or it has been changed"})
def partial_update(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot partial_update data which not yours"})
else:
data = self.request.data
if binsize.objects.filter(openid=self.request.auth.openid, bin_size=data['bin_size'], is_delete=False).exists():
if binproperty.objects.filter(Q(openid=self.request.auth.openid, bin_property=data['bin_property'], is_delete=False) |
Q(openid='init_data', bin_property=data['bin_property'], is_delete=False)).exists():
serializer = self.get_serializer(qs, data=data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
else:
raise APIException({"detail": "Bin property does not exists or it has been changed"})
else:
raise APIException({"detail": "Bin size does not exists or it has been changed"})
def destroy(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot delete data which not yours"})
else:
qs.is_delete = True
qs.save()
serializer = self.get_serializer(qs, many=False)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
class FileDownloadView(viewsets.ModelViewSet):
renderer_classes = (FileRenderCN, ) + tuple(api_settings.DEFAULT_RENDERER_CLASSES)
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
def get_project(self):
try:
id = self.kwargs.get('pk')
return id
except:
return None
def get_queryset(self):
id = self.get_project()
if self.request.user:
if id is None:
return ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False)
else:
return ListModel.objects.filter(openid=self.request.auth.openid, id=id, is_delete=False)
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list']:
return serializers.FileRenderSerializer
else:
return self.http_method_not_allowed(request=self.request)
def get_lang(self, data):
lang = self.request.META.get('HTTP_LANGUAGE')
if lang:
if lang == 'zh-hans':
return FileRenderCN().render(data)
else:
return FileRenderEN().render(data)
else:
return FileRenderEN().render(data)
def list(self, request, *args, **kwargs):
from datetime import datetime
dt = datetime.now()
data = (
FileRenderSerializer(instance).data
for instance in self.filter_queryset(self.get_queryset())
)
renderer = self.get_lang(data)
response = StreamingHttpResponse(
renderer,
content_type="text/csv"
)
response['Content-Disposition'] = "attachment; filename='binset_{}.csv'".format(str(dt.strftime('%Y%m%d%H%M%S%f')))
return response
View File
-4
View File
@@ -1,4 +0,0 @@
from django.contrib import admin
from . models import ListModel
admin.site.register(ListModel)
-4
View File
@@ -1,4 +0,0 @@
from django.apps import AppConfig
class BinsizeConfig(AppConfig):
name = 'binsize'
-42
View File
@@ -1,42 +0,0 @@
from rest_framework_csv.renderers import CSVStreamingRenderer
def file_headers():
return [
'bin_size',
'bin_size_w',
'bin_size_d',
'bin_size_h',
'creater',
'create_time',
'update_time'
]
def cn_data_header():
return dict([
('bin_size', u'库位尺寸名称'),
('bin_size_w', u'库位尺寸长度'),
('bin_size_d', u'库位尺寸宽度'),
('bin_size_h', u'库位尺寸高度'),
('creater', u'创建人'),
('create_time', u'创建时间'),
('update_time', u'更新时间'),
])
def en_data_header():
return dict([
('bin_size', u'Bin Size'),
('bin_size_w', u'Bin Wide'),
('bin_size_d', u'Bin Depth'),
('bin_size_h', u'Bin Height'),
('creater', u'Creater'),
('create_time', u'Create Time'),
('update_time', u'Update Time'),
])
class FileRenderCN(CSVStreamingRenderer):
header = file_headers()
labels = cn_data_header()
class FileRenderEN(CSVStreamingRenderer):
header = file_headers()
labels = en_data_header()
-17
View File
@@ -1,17 +0,0 @@
from django_filters import FilterSet
from .models import ListModel
class Filter(FilterSet):
class Meta:
model = ListModel
fields = {
"id": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"bin_size": ['exact', 'iexact', 'contains', 'icontains'],
"bin_size_w": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"bin_size_d": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"bin_size_h": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"creater": ['exact', 'iexact', 'contains', 'icontains'],
"is_delete": ['exact', 'iexact'],
"create_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range'],
"update_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range']
}
View File
-21
View File
@@ -1,21 +0,0 @@
from django.db import models
class ListModel(models.Model):
bin_size = models.CharField(max_length=255, verbose_name="Bin Name")
bin_size_w = models.FloatField(default=0, verbose_name="Bin Width")
bin_size_d = models.FloatField(default=0, verbose_name="Bin Depth")
bin_size_h = models.FloatField(default=0, verbose_name="Bin Height")
creater = models.CharField(max_length=255, verbose_name="Who created")
openid = models.CharField(max_length=255, verbose_name="Openid")
is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
class Meta:
db_table = 'binsize'
verbose_name = 'data id'
verbose_name_plural = "data id"
ordering = ['-id']
def __str__(self):
return self.pk
-64
View File
@@ -1,64 +0,0 @@
from rest_framework import serializers
from .models import ListModel
from utils import datasolve
class BinsizeGetSerializer(serializers.ModelSerializer):
bin_size = serializers.CharField(read_only=True, required=False)
bin_size_w = serializers.FloatField(read_only=True, required=False)
bin_size_d = serializers.FloatField(read_only=True, required=False)
bin_size_h = serializers.FloatField(read_only=True, required=False)
creater = serializers.CharField(read_only=True, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', ]
class BinsizePostSerializer(serializers.ModelSerializer):
openid = serializers.CharField(read_only=False, required=False, validators=[datasolve.openid_validate])
bin_size = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
bin_size_w = serializers.FloatField(read_only=False, required=True, validators=[datasolve.data_validate])
bin_size_d = serializers.FloatField(read_only=False, required=True, validators=[datasolve.data_validate])
bin_size_h = serializers.FloatField(read_only=False, required=True, validators=[datasolve.data_validate])
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class BinsizeUpdateSerializer(serializers.ModelSerializer):
bin_size = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
bin_size_w = serializers.FloatField(read_only=False, required=True, validators=[datasolve.data_validate])
bin_size_d = serializers.FloatField(read_only=False, required=True, validators=[datasolve.data_validate])
bin_size_h = serializers.FloatField(read_only=False, required=True, validators=[datasolve.data_validate])
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class BinsizePartialUpdateSerializer(serializers.ModelSerializer):
bin_size = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
bin_size_w = serializers.FloatField(read_only=False, required=False, validators=[datasolve.data_validate])
bin_size_d = serializers.FloatField(read_only=False, required=False, validators=[datasolve.data_validate])
bin_size_h = serializers.FloatField(read_only=False, required=False, validators=[datasolve.data_validate])
creater = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class FileRenderSerializer(serializers.ModelSerializer):
bin_size = serializers.CharField(read_only=False, required=False)
bin_size_w = serializers.FloatField(read_only=False, required=False)
bin_size_d = serializers.FloatField(read_only=False, required=False)
bin_size_h = serializers.FloatField(read_only=False, required=False)
creater = serializers.CharField(read_only=False, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = ListModel
ref_name = 'BinSizeFileRenderSerializer'
exclude = ['openid', 'is_delete', ]
View File
-13
View File
@@ -1,13 +0,0 @@
from django.urls import path, re_path
from . import views
urlpatterns = [
path(r'', views.APIViewSet.as_view({"get": "list", "post": "create"}), name="binsize"),
path(r'file/', views.FileDownloadView.as_view({"get": "list"}), name="binsizefiledownload"),
re_path(r'^(?P<pk>\d+)/$', views.APIViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
}), name="binsize_1")
]
-168
View File
@@ -1,168 +0,0 @@
from rest_framework import viewsets
from .models import ListModel
from . import serializers
from utils.page import MyPageNumberPagination
from rest_framework.filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.response import Response
from .filter import Filter
from rest_framework.exceptions import APIException
from .serializers import FileRenderSerializer
from django.http import StreamingHttpResponse
from .files import FileRenderCN, FileRenderEN
from rest_framework.settings import api_settings
class APIViewSet(viewsets.ModelViewSet):
"""
retrieve:
Response a data listget
list:
Response a data listall
create:
Create a data linepost
delete:
Delete a data linedelete)
partial_update:
Partial_update a datapatchpartial_update
update:
Update a dataputupdate
"""
pagination_class = MyPageNumberPagination
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
def get_project(self):
try:
id = self.kwargs.get('pk')
return id
except:
return None
def get_queryset(self):
id = self.get_project()
if self.request.user:
if id is None:
return ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False)
else:
return ListModel.objects.filter(openid=self.request.auth.openid, id=id, is_delete=False)
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list', 'retrieve', 'destroy']:
return serializers.BinsizeGetSerializer
elif self.action in ['create']:
return serializers.BinsizePostSerializer
elif self.action in ['update']:
return serializers.BinsizeUpdateSerializer
elif self.action in ['partial_update']:
return serializers.BinsizePartialUpdateSerializer
else:
return self.http_method_not_allowed(request=self.request)
def create(self, request, *args, **kwargs):
data = self.request.data
data['openid'] = self.request.auth.openid
if ListModel.objects.filter(openid=data['openid'], bin_size=data['bin_size'], is_delete=False).exists():
raise APIException({"detail": "Data exists"})
else:
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
def update(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot update data which not yours"})
else:
data = self.request.data
serializer = self.get_serializer(qs, data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
def partial_update(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot partial_update data which not yours"})
else:
data = self.request.data
serializer = self.get_serializer(qs, data=data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
def destroy(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot delete data which not yours"})
else:
qs.is_delete = True
qs.save()
serializer = self.get_serializer(qs, many=False)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
class FileDownloadView(viewsets.ModelViewSet):
renderer_classes = (FileRenderCN, ) + tuple(api_settings.DEFAULT_RENDERER_CLASSES)
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
def get_project(self):
try:
id = self.kwargs.get('pk')
return id
except:
return None
def get_queryset(self):
id = self.get_project()
if self.request.user:
if id is None:
return ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False)
else:
return ListModel.objects.filter(openid=self.request.auth.openid, id=id, is_delete=False)
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list']:
return serializers.FileRenderSerializer
else:
return self.http_method_not_allowed(request=self.request)
def get_lang(self, data):
lang = self.request.META.get('HTTP_LANGUAGE')
if lang:
if lang == 'zh-hans':
return FileRenderCN().render(data)
else:
return FileRenderEN().render(data)
else:
return FileRenderEN().render(data)
def list(self, request, *args, **kwargs):
from datetime import datetime
dt = datetime.now()
data = (
FileRenderSerializer(instance).data
for instance in self.filter_queryset(self.get_queryset())
)
renderer = self.get_lang(data)
response = StreamingHttpResponse(
renderer,
content_type="text/csv"
)
response['Content-Disposition'] = "attachment; filename='binsize_{}.csv'".format(str(dt.strftime('%Y%m%d%H%M%S%f')))
return response
View File
-4
View File
@@ -1,4 +0,0 @@
from django.contrib import admin
from . models import ListModel
admin.site.register(ListModel)
-4
View File
@@ -1,4 +0,0 @@
from django.apps import AppConfig
class CapitalConfig(AppConfig):
name = 'capital'
-38
View File
@@ -1,38 +0,0 @@
from rest_framework_csv.renderers import CSVStreamingRenderer
def file_headers():
return [
'capital_name',
'capital_qty',
'capital_cost',
'creater',
'create_time',
'update_time'
]
def cn_data_header():
return dict([
('capital_name', u'资产名称'),
('capital_qty', u'资产数量'),
('capital_cost', u'资产成本'),
('creater', u'创建人'),
('create_time', u'创建时间'),
('update_time', u'更新时间')
])
def en_data_header():
return dict([
('capital_name', u'Capital Name'),
('capital_qty', u'Capital Qty'),
('capital_cost', u'Capital Cost'),
('creater', u'Creater'),
('create_time', u'Create Time'),
('update_time', u'Update Time')
])
class FileRenderCN(CSVStreamingRenderer):
header = file_headers()
labels = cn_data_header()
class FileRenderEN(CSVStreamingRenderer):
header = file_headers()
labels = en_data_header()
-16
View File
@@ -1,16 +0,0 @@
from django_filters import FilterSet
from .models import ListModel
class Filter(FilterSet):
class Meta:
model = ListModel
fields = {
"id": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"capital_name": ['exact', 'iexact', 'contains', 'icontains'],
"capital_qty": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"capital_cost": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"creater": ['exact', 'iexact', 'contains', 'icontains'],
"is_delete": ['exact', 'iexact'],
"create_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range'],
"update_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range']
}
View File
-20
View File
@@ -1,20 +0,0 @@
from django.db import models
class ListModel(models.Model):
capital_name = models.CharField(max_length=255, verbose_name="Capital Name")
capital_qty = models.BigIntegerField(default=0, verbose_name="Capital Qty")
capital_cost = models.FloatField(default=0, verbose_name="Capital Cost")
creater = models.CharField(max_length=255, verbose_name="Who Created")
openid = models.CharField(max_length=255, verbose_name="Openid")
is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
class Meta:
db_table = 'capital'
verbose_name = 'data id'
verbose_name_plural = "data id"
ordering = ['-id']
def __str__(self):
return self.pk
-59
View File
@@ -1,59 +0,0 @@
from rest_framework import serializers
from .models import ListModel
from utils import datasolve
class CapitalGetSerializer(serializers.ModelSerializer):
capital_name = serializers.CharField(read_only=True, required=False)
capital_qty = serializers.IntegerField(read_only=True, required=False)
capital_cost = serializers.FloatField(read_only=True, required=False)
creater = serializers.CharField(read_only=True, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'openid', ]
class CapitalPostSerializer(serializers.ModelSerializer):
openid = serializers.CharField(read_only=False, required=False, validators=[datasolve.openid_validate])
capital_name = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
capital_qty = serializers.IntegerField(read_only=False, required=True, validators=[datasolve.data_validate])
capital_cost = serializers.FloatField(read_only=False, required=True, validators=[datasolve.data_validate])
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class CapitalUpdateSerializer(serializers.ModelSerializer):
capital_name = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
capital_qty = serializers.IntegerField(read_only=False, required=True, validators=[datasolve.data_validate])
capital_cost = serializers.FloatField(read_only=False, required=True, validators=[datasolve.data_validate])
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class CapitalPartialUpdateSerializer(serializers.ModelSerializer):
capital_name = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
capital_qty = serializers.IntegerField(read_only=False, required=False, validators=[datasolve.data_validate])
capital_cost = serializers.FloatField(read_only=False, required=False, validators=[datasolve.data_validate])
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class FileRenderSerializer(serializers.ModelSerializer):
capital_name = serializers.CharField(read_only=False, required=False)
capital_qty = serializers.IntegerField(read_only=False, required=False)
capital_cost = serializers.FloatField(read_only=False, required=False)
creater = serializers.CharField(read_only=False, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = ListModel
ref_name = 'CapitalFileRenderSerializer'
exclude = ['openid', 'is_delete', ]
View File
-13
View File
@@ -1,13 +0,0 @@
from django.urls import path, re_path
from . import views
urlpatterns = [
path(r'', views.APIViewSet.as_view({"get": "list", "post": "create"}), name="capital"),
path(r'file/', views.FileDownloadView.as_view({"get": "list"}), name="capitalfiledownload"),
re_path(r'^(?P<pk>\d+)/$', views.APIViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
}), name="capital_1")
]
-165
View File
@@ -1,165 +0,0 @@
from rest_framework import viewsets
from .models import ListModel
from . import serializers
from utils.page import MyPageNumberPagination
from rest_framework.filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.response import Response
from .filter import Filter
from rest_framework.exceptions import APIException
from .serializers import FileRenderSerializer
from django.http import StreamingHttpResponse
from .files import FileRenderCN, FileRenderEN
from rest_framework.settings import api_settings
class APIViewSet(viewsets.ModelViewSet):
"""
retrieve:
Response a data listget
list:
Response a data listall
create:
Create a data linepost
delete:
Delete a data linedelete)
partial_update:
Partial_update a datapatchpartial_update
update:
Update a dataputupdate
"""
pagination_class = MyPageNumberPagination
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
def get_project(self):
try:
id = self.kwargs.get('pk')
return id
except:
return None
def get_queryset(self):
id = self.get_project()
if self.request.user:
if id is None:
return ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False)
else:
return ListModel.objects.filter(openid=self.request.auth.openid, id=id, is_delete=False)
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list', 'retrieve', 'destroy']:
return serializers.CapitalGetSerializer
elif self.action in ['create']:
return serializers.CapitalPostSerializer
elif self.action in ['update']:
return serializers.CapitalUpdateSerializer
elif self.action in ['partial_update']:
return serializers.CapitalPartialUpdateSerializer
else:
return self.http_method_not_allowed(request=self.request)
def create(self, request, *args, **kwargs):
data = self.request.data
data['openid'] = self.request.auth.openid
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
def update(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot update data which not yours"})
else:
data = self.request.data
serializer = self.get_serializer(qs, data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
def partial_update(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot partial_update data which not yours"})
else:
data = self.request.data
serializer = self.get_serializer(qs, data=data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
def destroy(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot delete data which not yours"})
else:
qs.is_delete = True
qs.save()
serializer = self.get_serializer(qs, many=False)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
class FileDownloadView(viewsets.ModelViewSet):
renderer_classes = (FileRenderCN, ) + tuple(api_settings.DEFAULT_RENDERER_CLASSES)
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
def get_project(self):
try:
id = self.kwargs.get('pk')
return id
except:
return None
def get_queryset(self):
id = self.get_project()
if self.request.user:
if id is None:
return ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False)
else:
return ListModel.objects.filter(openid=self.request.auth.openid, id=id, is_delete=False)
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list']:
return serializers.FileRenderSerializer
else:
return self.http_method_not_allowed(request=self.request)
def get_lang(self, data):
lang = self.request.META.get('HTTP_LANGUAGE')
if lang:
if lang == 'zh-hans':
return FileRenderCN().render(data)
else:
return FileRenderEN().render(data)
else:
return FileRenderEN().render(data)
def list(self, request, *args, **kwargs):
from datetime import datetime
dt = datetime.now()
data = (
FileRenderSerializer(instance).data
for instance in self.filter_queryset(self.get_queryset())
)
renderer = self.get_lang(data)
response = StreamingHttpResponse(
renderer,
content_type="text/csv"
)
response['Content-Disposition'] = "attachment; filename='capital_{}.csv'".format(str(dt.strftime('%Y%m%d%H%M%S%f')))
return response
View File
-4
View File
@@ -1,4 +0,0 @@
from django.contrib import admin
from . models import ListModel
admin.site.register(ListModel)
-5
View File
@@ -1,5 +0,0 @@
from django.apps import AppConfig
class ChatConfig(AppConfig):
name = 'chat'
-14
View File
@@ -1,14 +0,0 @@
from django_filters import FilterSet
from .models import ListModel
class Filter(FilterSet):
class Meta:
model = ListModel
fields = {
"id": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"read": ['exact', 'iexact'],
"detail": ['exact', 'iexact', 'contains', 'icontains'],
"is_delete": ['exact', 'iexact'],
"create_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range'],
"update_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range']
}
View File
-19
View File
@@ -1,19 +0,0 @@
from django.db import models
class ListModel(models.Model):
sender = models.CharField(max_length=100, verbose_name='Sender')
receiver = models.CharField(max_length=100, verbose_name='Receiver')
read = models.BooleanField(default=False, verbose_name="Readed")
detail = models.CharField(max_length=100, verbose_name='Chat text')
is_delete = models.BooleanField(default=False, verbose_name='Delete label')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='Create time')
update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name='Update time')
class Meta:
db_table = 'chat'
verbose_name = 'data id'
verbose_name_plural = "data id"
ordering = ['-id']
def __str__(self):
return self.pk
-14
View File
@@ -1,14 +0,0 @@
from rest_framework import serializers
from .models import ListModel
class ChatGetSerializer(serializers.ModelSerializer):
sender = serializers.CharField(read_only=True, required=False)
receiver = serializers.CharField(read_only=True, required=False)
read = serializers.BooleanField(read_only=True, required=False)
detail = serializers.CharField(read_only=True, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = ListModel
exclude = ['is_delete', ]
read_only_fields = ['id', ]
View File
-7
View File
@@ -1,7 +0,0 @@
from django.urls import path
from . import views
urlpatterns = [
path(r'', views.ChatViewSet.as_view({"get": "list"}), name="chat"),
path(r'read/', views.ReadAPI.as_view({"get": "list"}), name='read')
]
-57
View File
@@ -1,57 +0,0 @@
from django.db.models import Q
from rest_framework import viewsets
from .models import ListModel
from . import serializers
from utils.page import MyPageNumberPagination
from rest_framework.filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from .filter import Filter
class ChatViewSet(viewsets.ModelViewSet):
"""
list:
Response a data listall
"""
pagination_class = MyPageNumberPagination
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
def get_queryset(self):
if self.request.user:
sender = str(self.request.GET.get('sender', '')) + '-' + self.request.auth.openid
receiver = str(self.request.GET.get('receiver', '')) + '-' + self.request.auth.openid
if ListModel.objects.filter(sender=receiver, receiver=sender, read=False).exists():
ListModel.objects.filter(sender=receiver, receiver=sender, read=False).update(read=True)
return ListModel.objects.filter(Q(sender=sender, receiver=receiver) | Q(sender=receiver, receiver=sender))
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list']:
return serializers.ChatGetSerializer
else:
return self.http_method_not_allowed(request=self.request)
class ReadAPI(viewsets.ModelViewSet):
"""
list:
Response a data listall
"""
pagination_class = MyPageNumberPagination
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
def get_queryset(self):
if self.request.user:
sender = str(self.request.GET.get('sender', '')) + '-' + self.request.auth.openid
return ListModel.objects.filter(receiver=sender, read=False)
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list']:
return serializers.ChatGetSerializer
else:
return self.http_method_not_allowed(request=self.request)
View File
-4
View File
@@ -1,4 +0,0 @@
from django.contrib import admin
from . models import ListModel
admin.site.register(ListModel)
-4
View File
@@ -1,4 +0,0 @@
from django.apps import AppConfig
class CompanyConfig(AppConfig):
name = 'company'
-18
View File
@@ -1,18 +0,0 @@
from django_filters import FilterSet
from .models import ListModel
class Filter(FilterSet):
class Meta:
model = ListModel
fields = {
"id": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"company_name": ['exact', 'iexact', 'contains', 'icontains'],
"company_city": ['exact', 'iexact', 'contains', 'icontains'],
"company_address": ['exact', 'iexact', 'contains', 'icontains'],
"company_contact": ['exact', 'iexact', 'contains', 'icontains'],
"company_manager": ['exact', 'iexact', 'contains', 'icontains'],
"creater": ['exact', 'iexact', 'contains', 'icontains'],
"is_delete": ['exact', 'iexact'],
"create_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range'],
"update_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range']
}
View File
-22
View File
@@ -1,22 +0,0 @@
from django.db import models
class ListModel(models.Model):
company_name = models.CharField(max_length=255, verbose_name="Company Name")
company_city = models.CharField(max_length=255, verbose_name="Company City")
company_address = models.CharField(max_length=255, verbose_name="Company Address")
company_contact = models.BigIntegerField(default=0, verbose_name="Company Contact")
company_manager = models.CharField(max_length=255, verbose_name="Company Manager")
creater = models.CharField(max_length=255, verbose_name="Who Created")
openid = models.CharField(max_length=255, verbose_name="Openid")
is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
create_time = models.DateTimeField(auto_now_add=True, verbose_name="Create Time")
update_time = models.DateTimeField(auto_now=True, blank=True, null=True, verbose_name="Update Time")
class Meta:
db_table = 'company'
verbose_name = 'data id'
verbose_name_plural = "data id"
ordering = ['company_name']
def __str__(self):
return self.pk
-54
View File
@@ -1,54 +0,0 @@
from rest_framework import serializers
from .models import ListModel
from utils import datasolve
class CompanyGetSerializer(serializers.ModelSerializer):
company_name = serializers.CharField(read_only=True, required=False)
company_city = serializers.CharField(read_only=True, required=False)
company_address = serializers.CharField(read_only=True, required=False)
company_contact = serializers.IntegerField(read_only=True, required=False)
company_manager = serializers.CharField(read_only=True, required=False)
creater = serializers.CharField(read_only=True, required=False)
create_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
update_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M:%S')
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id']
class CompanyPostSerializer(serializers.ModelSerializer):
openid = serializers.CharField(read_only=False, required=False, validators=[datasolve.openid_validate])
company_name = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
company_city = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
company_address = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
company_contact = serializers.IntegerField(read_only=False, required=True, validators=[datasolve.data_validate])
company_manager = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class CompanyUpdateSerializer(serializers.ModelSerializer):
company_name = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
company_city = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
company_address = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
company_contact = serializers.IntegerField(read_only=False, required=True, validators=[datasolve.data_validate])
company_manager = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
creater = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
class CompanyPartialUpdateSerializer(serializers.ModelSerializer):
company_name = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
company_city = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
company_address = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
company_contact = serializers.IntegerField(read_only=False, required=False, validators=[datasolve.data_validate])
company_manager = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
creater = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
class Meta:
model = ListModel
exclude = ['openid', 'is_delete', ]
read_only_fields = ['id', 'create_time', 'update_time', ]
View File
-12
View File
@@ -1,12 +0,0 @@
from django.urls import path, re_path
from . import views
urlpatterns = [
path(r'', views.APIViewSet.as_view({"get": "list", "post": "create"}), name="company"),
re_path(r'^(?P<pk>\d+)/$', views.APIViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
}), name="company_1")
]
-114
View File
@@ -1,114 +0,0 @@
from rest_framework import viewsets
from .models import ListModel
from . import serializers
from utils.page import MyPageNumberPagination
from rest_framework.filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.response import Response
from .filter import Filter
from rest_framework.exceptions import APIException
class APIViewSet(viewsets.ModelViewSet):
"""
retrieve:
Response a data listget
list:
Response a data listall
create:
Create a data linepost
delete:
Delete a data linedelete)
partial_update:
Partial_update a datapatchpartial_update
update:
Update a dataputupdate
"""
pagination_class = MyPageNumberPagination
filter_backends = [DjangoFilterBackend, OrderingFilter, ]
ordering_fields = ['id', "create_time", "update_time", ]
filter_class = Filter
def get_project(self):
try:
id = self.kwargs.get('pk')
return id
except:
return None
def get_queryset(self):
id = self.get_project()
if self.request.user:
if id is None:
return ListModel.objects.filter(openid=self.request.auth.openid, is_delete=False)
else:
return ListModel.objects.filter(openid=self.request.auth.openid, id=id, is_delete=False)
else:
return ListModel.objects.none()
def get_serializer_class(self):
if self.action in ['list', 'retrieve', 'destroy']:
return serializers.CompanyGetSerializer
elif self.action in ['create']:
return serializers.CompanyPostSerializer
elif self.action in ['update']:
return serializers.CompanyUpdateSerializer
elif self.action in ['partial_update']:
return serializers.CompanyPartialUpdateSerializer
else:
return self.http_method_not_allowed(request=self.request)
def create(self, request, *args, **kwargs):
data = self.request.data
data['openid'] = self.request.auth.openid
if ListModel.objects.filter(openid=data['openid'], company_name=data['company_name'], is_delete=False).exists():
raise APIException({"detail": "Data exists"})
else:
if ListModel.objects.filter(openid=data['openid'], is_delete=False).count() >= 1:
raise APIException({"detail": "You Just Can Create 1 Company"})
else:
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
def update(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot update data which not yours"})
else:
data = self.request.data
serializer = self.get_serializer(qs, data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
def partial_update(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot partial_update data which not yours"})
else:
data = self.request.data
serializer = self.get_serializer(qs, data=data, partial=True)
serializer.is_valid(raise_exception=True)
serializer.save()
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
def destroy(self, request, pk):
qs = self.get_object()
if qs.openid != self.request.auth.openid:
raise APIException({"detail": "Cannot delete data which not yours"})
else:
qs.is_delete = True
qs.save()
serializer = self.get_serializer(qs, many=False)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=200, headers=headers)
View File
-4
View File
@@ -1,4 +0,0 @@
from django.contrib import admin
from . models import ListModel
admin.site.register(ListModel)
-4
View File
@@ -1,4 +0,0 @@
from django.apps import AppConfig
class CustomerConfig(AppConfig):
name = 'customer'
-49
View File
@@ -1,49 +0,0 @@
from rest_framework_csv.renderers import CSVStreamingRenderer
def file_headers():
return [
'customer_name',
'customer_city',
'customer_address',
'customer_contact',
'customer_manager',
'customer_level',
'creater',
'create_time',
'update_time'
]
def cn_data_header():
return dict([
('customer_name', u'客户名称'),
('customer_city', u'客户城市'),
('customer_address', u'详细地址'),
('customer_contact', u'联系电话'),
('customer_manager', u'负责人'),
('customer_level', u'客户等级'),
('creater', u'创建人'),
('create_time', u'创建时间'),
('update_time', u'更新时间'),
])
def en_data_header():
return dict([
('customer_name', u'Customer Name'),
('customer_city', u'Customer City'),
('customer_address', u'Customer Address'),
('customer_contact', u'Customer Contact'),
('customer_manager', u'Customer Manager'),
('customer_level', u'Customer Level'),
('creater', u'Creater'),
('create_time', u'Create Time'),
('update_time', u'Update Time'),
])
class FileRenderCN(CSVStreamingRenderer):
header = file_headers()
labels = cn_data_header()
class FileRenderEN(CSVStreamingRenderer):
header = file_headers()
labels = en_data_header()
-20
View File
@@ -1,20 +0,0 @@
from django_filters import FilterSet
from .models import ListModel
class Filter(FilterSet):
class Meta:
model = ListModel
fields = {
"id": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"customer_name": ['exact', 'iexact', 'contains', 'icontains'],
"customer_city": ['exact', 'iexact', 'contains', 'icontains'],
"customer_address": ['exact', 'iexact', 'contains', 'icontains'],
"customer_contact": ['exact', 'iexact', 'contains', 'icontains'],
"customer_manager": ['exact', 'iexact', 'contains', 'icontains'],
"customer_level": ['exact', 'iexact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
"creater": ['exact', 'iexact', 'contains', 'icontains'],
"is_delete": ['exact', 'iexact'],
"create_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range'],
"update_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range']
}

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