forked from erp-dev/erp
init
This commit is contained in:
8
.env
Normal file
8
.env
Normal file
@@ -0,0 +1,8 @@
|
||||
SECRET_KEY=testing_$weak_secret_is_allowd
|
||||
DEBUG=True
|
||||
ALLOWED_HOSTS=*,
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_NAME=myapp
|
||||
DB_USER=postgres
|
||||
DB_PASSWORD=postgres
|
||||
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
# Python-generated files
|
||||
__pycache__/
|
||||
*.py[oc]
|
||||
build/
|
||||
dist/
|
||||
wheels/
|
||||
*.egg-info
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
5
.idea/.gitignore
generated
vendored
Normal file
5
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
6
.idea/copilot.data.migration.agent.xml
generated
Normal file
6
.idea/copilot.data.migration.agent.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AgentMigrationStateService">
|
||||
<option name="migrationStatus" value="COMPLETED" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/copilot.data.migration.ask.xml
generated
Normal file
6
.idea/copilot.data.migration.ask.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AskMigrationStateService">
|
||||
<option name="migrationStatus" value="COMPLETED" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/copilot.data.migration.ask2agent.xml
generated
Normal file
6
.idea/copilot.data.migration.ask2agent.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Ask2AgentMigrationStateService">
|
||||
<option name="migrationStatus" value="COMPLETED" />
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/copilot.data.migration.edit.xml
generated
Normal file
6
.idea/copilot.data.migration.edit.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="EditMigrationStateService">
|
||||
<option name="migrationStatus" value="COMPLETED" />
|
||||
</component>
|
||||
</project>
|
||||
20
.idea/dataSources.local.xml
generated
Normal file
20
.idea/dataSources.local.xml
generated
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="dataSourceStorageLocal" created-in="PY-252.27397.106">
|
||||
<data-source name="myapp@localhost" uuid="15dcd0e2-d09f-417a-adb8-9c908c90dd7e">
|
||||
<database-info product="PostgreSQL" version="16.10" jdbc-version="4.2" driver-name="PostgreSQL JDBC Driver" driver-version="42.7.3" dbms="POSTGRES" exact-version="16.10" exact-driver-version="42.7">
|
||||
<identifier-quote-string>"</identifier-quote-string>
|
||||
</database-info>
|
||||
<case-sensitivity plain-identifiers="lower" quoted-identifiers="exact" />
|
||||
<secret-storage>master_key</secret-storage>
|
||||
<user-name>postgres</user-name>
|
||||
<schema-mapping>
|
||||
<introspection-scope>
|
||||
<node kind="database" qname="@">
|
||||
<node kind="schema" qname="@" />
|
||||
</node>
|
||||
</introspection-scope>
|
||||
</schema-mapping>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
12
.idea/dataSources.xml
generated
Normal file
12
.idea/dataSources.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||
<data-source source="LOCAL" name="myapp@localhost" uuid="15dcd0e2-d09f-417a-adb8-9c908c90dd7e">
|
||||
<driver-ref>postgresql</driver-ref>
|
||||
<synchronize>true</synchronize>
|
||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
||||
<jdbc-url>jdbc:postgresql://localhost:5432/myapp</jdbc-url>
|
||||
<working-dir>$ProjectFileDir$</working-dir>
|
||||
</data-source>
|
||||
</component>
|
||||
</project>
|
||||
5720
.idea/dataSources/15dcd0e2-d09f-417a-adb8-9c908c90dd7e.xml
generated
Normal file
5720
.idea/dataSources/15dcd0e2-d09f-417a-adb8-9c908c90dd7e.xml
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
#n:myapp
|
||||
@@ -0,0 +1,2 @@
|
||||
#n:information_schema
|
||||
!<md> [null, 0, null, null, -2147483648, -2147483648]
|
||||
@@ -0,0 +1,2 @@
|
||||
#n:pg_catalog
|
||||
!<md> [null, 0, null, null, -2147483648, -2147483648]
|
||||
@@ -0,0 +1,2 @@
|
||||
#n:public
|
||||
!<md> [866, 0, null, null, -2147483648, -2147483648]
|
||||
14
.idea/flower.iml
generated
Normal file
14
.idea/flower.iml
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="PYTHON_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||
</content>
|
||||
<orderEntry type="jdk" jdkName="Python 3.14 (flower)" jdkType="Python SDK" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
<component name="PyDocumentationSettings">
|
||||
<option name="format" value="PLAIN" />
|
||||
<option name="myDocStringFormat" value="Plain" />
|
||||
</component>
|
||||
</module>
|
||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<settings>
|
||||
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||
<version value="1.0" />
|
||||
</settings>
|
||||
</component>
|
||||
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Black">
|
||||
<option name="sdkName" value="Python 3.14 (flower)" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.14 (flower)" project-jdk-type="Python SDK" />
|
||||
</project>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/flower.iml" filepath="$PROJECT_DIR$/.idea/flower.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
1
.python-version
Normal file
1
.python-version
Normal file
@@ -0,0 +1 @@
|
||||
3.14
|
||||
0
basic_info/__init__.py
Normal file
0
basic_info/__init__.py
Normal file
82
basic_info/admin.py
Normal file
82
basic_info/admin.py
Normal file
@@ -0,0 +1,82 @@
|
||||
from django.contrib import admin
|
||||
from . import models
|
||||
|
||||
|
||||
@admin.register(models.Supplier)
|
||||
class SupplierAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'area', 'email', 'mobile')
|
||||
search_fields = ('name', 'area', 'email', 'mobile')
|
||||
|
||||
|
||||
@admin.register(models.ProductCategory)
|
||||
class ProductCategoryAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'product_prefix', 'description')
|
||||
search_fields = ('name',)
|
||||
|
||||
|
||||
@admin.register(models.Product)
|
||||
class ProductAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
'name',
|
||||
'category',
|
||||
'human_id',
|
||||
'color',
|
||||
'width_size',
|
||||
'transform_rate',
|
||||
'single_price_in',
|
||||
'single_price_out',
|
||||
)
|
||||
search_fields = ('name', 'human_id')
|
||||
list_filter = ('category',)
|
||||
|
||||
|
||||
@admin.register(models.BankAccount)
|
||||
class BankAccountAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'auto_number')
|
||||
search_fields = ('name', 'auto_number')
|
||||
|
||||
|
||||
@admin.register(models.WareHouse)
|
||||
class WareHouseAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'location', 'area', 'mobile')
|
||||
search_fields = ('name', 'area')
|
||||
|
||||
|
||||
@admin.register(models.Customer)
|
||||
class CustomerAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'area', 'email', 'mobile', 'total_debt')
|
||||
search_fields = ('name', 'area', 'email', 'mobile')
|
||||
|
||||
@admin.display(boolean=False, description='累欠金额')
|
||||
def total_debt(self, obj):
|
||||
return '0 (动态逻辑字段待实现)'
|
||||
|
||||
|
||||
@admin.register(models.Employee)
|
||||
class EmployeeAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'mobile', 'status', 'job_type', 'sys_user')
|
||||
search_fields = ('name', 'mobile')
|
||||
list_filter = (
|
||||
'job_type',
|
||||
'status',
|
||||
)
|
||||
|
||||
|
||||
@admin.register(models.DeviceInfo)
|
||||
class DeviceInfoAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'type', 'is_occupied', 'status')
|
||||
search_fields = ('name', 'start_working_at', 'stop_working_at')
|
||||
list_filter = ('type', 'status')
|
||||
|
||||
|
||||
@admin.register(models.VehicleType)
|
||||
class VehicleTypeAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'description')
|
||||
search_fields = ('name',)
|
||||
|
||||
|
||||
@admin.register(models.VehicleTransportRecord)
|
||||
class VehicleTransportRecordAdmin(admin.ModelAdmin):
|
||||
list_display = ('driver_name', 'contact_number', 'delivery_date')
|
||||
search_fields = ('driver_name', 'contact_number')
|
||||
list_filter = ('vehicle_type',)
|
||||
7
basic_info/apps.py
Normal file
7
basic_info/apps.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class BasicInfoConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'basic_info'
|
||||
verbose_name = '基础资料'
|
||||
133
basic_info/migrations/0001_initial.py
Normal file
133
basic_info/migrations/0001_initial.py
Normal file
@@ -0,0 +1,133 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:06
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BankAccount',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='名称')),
|
||||
('auto_number', models.CharField(max_length=50, verbose_name='自动编号')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('attachment', models.FileField(blank=True, null=True, upload_to='bank_accounts/', verbose_name='附件')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '银行账户',
|
||||
'verbose_name_plural': '银行账户',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProductCategory',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='类别名称')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='类别描述')),
|
||||
('product_prefix', models.CharField(max_length=5, verbose_name='产品编号前缀')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '产品类别',
|
||||
'verbose_name_plural': '产品类别',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='ProductUnit',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=20, verbose_name='单位名称')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '产品单位',
|
||||
'verbose_name_plural': '产品单位',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Supplier',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='供应商名称')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='电子邮箱')),
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('contact', models.TextField(blank=True, null=True, verbose_name='联系人')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '供应商',
|
||||
'verbose_name_plural': '供应商',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='WareHouse',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='仓库名称')),
|
||||
('location', models.CharField(blank=True, max_length=200, null=True, verbose_name='仓库地址')),
|
||||
('contact', models.CharField(blank=True, max_length=100, null=True, verbose_name='联系人')),
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '仓库资料',
|
||||
'verbose_name_plural': '仓库资料',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Product',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='产品名')),
|
||||
('human_id', models.CharField(blank=True, max_length=100, verbose_name='产品编号')),
|
||||
('color', models.CharField(blank=True, max_length=50, null=True, verbose_name='颜色')),
|
||||
('width_size', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='宽幅')),
|
||||
('single_price', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='单价')),
|
||||
('spec', models.CharField(blank=True, max_length=100, null=True, verbose_name='规格')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='basic_info.productcategory', verbose_name='产品类别')),
|
||||
('unit', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='basic_info.productunit', verbose_name='单位')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '产品资料',
|
||||
'verbose_name_plural': '产品资料',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PurchaseOrder',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('order_date', models.DateField(verbose_name='订单日期')),
|
||||
('total_amount', models.DecimalField(decimal_places=2, max_digits=15, verbose_name='总金额')),
|
||||
('remarks', models.TextField(blank=True, null=True, verbose_name='备注')),
|
||||
('supplier', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='purchase_orders', to='basic_info.supplier', verbose_name='供应商')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '采购单',
|
||||
'verbose_name_plural': '采购单',
|
||||
},
|
||||
),
|
||||
]
|
||||
16
basic_info/migrations/0002_delete_purchaseorder.py
Normal file
16
basic_info/migrations/0002_delete_purchaseorder.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:11
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='PurchaseOrder',
|
||||
),
|
||||
]
|
||||
31
basic_info/migrations/0003_customer.py
Normal file
31
basic_info/migrations/0003_customer.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0002_delete_purchaseorder'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Customer',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='客户名称')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='电子邮箱')),
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('contact', models.TextField(blank=True, null=True, verbose_name='联系人')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '客户资料',
|
||||
'verbose_name_plural': '客户资料',
|
||||
},
|
||||
),
|
||||
]
|
||||
18
basic_info/migrations/0004_alter_customer_contact.py
Normal file
18
basic_info/migrations/0004_alter_customer_contact.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:15
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0003_customer'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='customer',
|
||||
name='contact',
|
||||
field=models.CharField(blank=True, null=True, verbose_name='联系人'),
|
||||
),
|
||||
]
|
||||
18
basic_info/migrations/0005_alter_customer_mobile.py
Normal file
18
basic_info/migrations/0005_alter_customer_mobile.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0004_alter_customer_contact'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='customer',
|
||||
name='mobile',
|
||||
field=models.CharField(max_length=20, verbose_name='手机'),
|
||||
),
|
||||
]
|
||||
33
basic_info/migrations/0006_employee.py
Normal file
33
basic_info/migrations/0006_employee.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0005_alter_customer_mobile'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Employee',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='员工姓名')),
|
||||
('job_type', models.CharField(choices=[('打纸', '打纸'), ('滚筒', '滚筒'), ('仓库', '仓库'), ('送货', '送货')], default='打纸', max_length=20, verbose_name='职位')),
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='电子邮箱')),
|
||||
('contact', models.CharField(blank=True, null=True, verbose_name='联系人')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('status', models.CharField(choices=[('在职', '在职'), ('离职', '离职')], default='在职', max_length=20, verbose_name='员工状态')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '员工资料',
|
||||
'verbose_name_plural': '员工资料',
|
||||
},
|
||||
),
|
||||
]
|
||||
17
basic_info/migrations/0007_remove_employee_contact.py
Normal file
17
basic_info/migrations/0007_remove_employee_contact.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:27
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0006_employee'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='employee',
|
||||
name='contact',
|
||||
),
|
||||
]
|
||||
17
basic_info/migrations/0008_remove_employee_email.py
Normal file
17
basic_info/migrations/0008_remove_employee_email.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:29
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0007_remove_employee_contact'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='employee',
|
||||
name='email',
|
||||
),
|
||||
]
|
||||
21
basic_info/migrations/0009_employee_sys_user.py
Normal file
21
basic_info/migrations/0009_employee_sys_user.py
Normal file
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 07:05
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0008_remove_employee_email'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='employee',
|
||||
name='sys_user',
|
||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='employee', to=settings.AUTH_USER_MODEL, verbose_name='系统用户'),
|
||||
),
|
||||
]
|
||||
32
basic_info/migrations/0010_deviceinfo.py
Normal file
32
basic_info/migrations/0010_deviceinfo.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 07:14
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0009_employee_sys_user'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='DeviceInfo',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='设备名称')),
|
||||
('type', models.CharField(choices=[('滚筒', '滚筒'), ('打印', '打印')], default='滚筒', max_length=20, verbose_name='设备类型')),
|
||||
('status', models.CharField(choices=[('使用中', '使用中'), ('停用', '停用'), ('维修中', '维修中')], default='使用中', max_length=20, verbose_name='设备状态')),
|
||||
('start_working_at', models.DateField(blank=True, null=True, verbose_name='开始服役日期')),
|
||||
('stop_working_at', models.DateField(blank=True, null=True, verbose_name='停止服役日期')),
|
||||
('is_occupied', models.BooleanField(default=False, verbose_name='是否被占用')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '设备信息',
|
||||
'verbose_name_plural': '设备信息',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,49 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 07:26
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0010_deviceinfo'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='VehicleType',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=50, verbose_name='车辆类型名称')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '车辆类型',
|
||||
'verbose_name_plural': '车辆类型',
|
||||
},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='deviceinfo',
|
||||
options={'verbose_name': '设备资料', 'verbose_name_plural': '设备资料'},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='VehicleTransportRecord',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('driver_name', models.CharField(max_length=100, verbose_name='司机姓名')),
|
||||
('contact_number', models.CharField(blank=True, max_length=20, null=True, verbose_name='联系电话')),
|
||||
('license_plate', models.CharField(blank=True, max_length=20, null=True, verbose_name='车牌号码')),
|
||||
('delivery_date', models.DateField(verbose_name='送货日期')),
|
||||
('vehicle_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='vehicles', to='basic_info.vehicletype', verbose_name='车次')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '司机车次',
|
||||
'verbose_name_plural': '司机车次',
|
||||
},
|
||||
),
|
||||
]
|
||||
19
basic_info/migrations/0012_alter_product_unit.py
Normal file
19
basic_info/migrations/0012_alter_product_unit.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 08:58
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0011_vehicletype_alter_deviceinfo_options_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='unit',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='basic_info.productunit', verbose_name='主单位'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,36 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 09:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0012_alter_product_unit'),
|
||||
('stock', '0018_remove_inventory_unit'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='product',
|
||||
name='unit',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='main_unit',
|
||||
field=models.IntegerField(choices=[(1, '米'), (2, '码'), (3, '公斤')], default=1, verbose_name='主单位'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='sub_unit',
|
||||
field=models.IntegerField(blank=True, choices=[(1, '米'), (2, '码'), (3, '公斤')], null=True, verbose_name='辅单位'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='transform_rate',
|
||||
field=models.DecimalField(blank=True, decimal_places=4, max_digits=10, null=True, verbose_name='转换率(主单位->辅单位)'),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='ProductUnit',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,31 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 09:30
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0013_remove_product_unit_product_main_unit_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='product',
|
||||
name='main_unit',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='product',
|
||||
name='sub_unit',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='single_price',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='单价(米)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='transform_rate',
|
||||
field=models.DecimalField(blank=True, decimal_places=4, max_digits=10, null=True, verbose_name='公斤转换率'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,27 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 09:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0014_remove_product_main_unit_remove_product_sub_unit_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='product',
|
||||
name='single_price',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='single_price_in',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='参考进价'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='single_price_out',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='参考售价'),
|
||||
),
|
||||
]
|
||||
0
basic_info/migrations/__init__.py
Normal file
0
basic_info/migrations/__init__.py
Normal file
285
basic_info/models.py
Normal file
285
basic_info/models.py
Normal file
@@ -0,0 +1,285 @@
|
||||
from decimal import Decimal
|
||||
|
||||
from django.db import models
|
||||
from flower.common import ModelBase
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
METER_TO_YARD_RATE = 0.9144
|
||||
YARD_TO_METER_RATE = 1.09361
|
||||
|
||||
|
||||
class VehicleType(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=50, verbose_name='车辆类型名称')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '车辆类型'
|
||||
verbose_name_plural = '车辆类型'
|
||||
|
||||
|
||||
class WareHouse(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=100, verbose_name='仓库名称')
|
||||
location = models.CharField(max_length=200, blank=True, null=True, verbose_name='仓库地址')
|
||||
contact = models.CharField(max_length=100, blank=True, null=True, verbose_name='联系人')
|
||||
mobile = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机')
|
||||
area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '仓库资料'
|
||||
verbose_name_plural = '仓库资料'
|
||||
|
||||
|
||||
class ProductUnitEnum(models.IntegerChoices):
|
||||
METER = 1, '米'
|
||||
YARD = 2, '码'
|
||||
KG = 3, '公斤'
|
||||
|
||||
|
||||
class Supplier(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=100, verbose_name='供应商名称')
|
||||
area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
|
||||
email = models.EmailField(blank=True, null=True, verbose_name='电子邮箱')
|
||||
mobile = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机')
|
||||
contact = models.TextField(blank=True, null=True, verbose_name='联系人')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '供应商'
|
||||
verbose_name_plural = '供应商'
|
||||
|
||||
|
||||
class BankAccount(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=100, verbose_name='名称')
|
||||
auto_number = models.CharField(max_length=50, verbose_name='自动编号')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
attachment = models.FileField(upload_to='bank_accounts/', blank=True, null=True, verbose_name='附件')
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.name} - {self.auto_number}'
|
||||
|
||||
class Meta:
|
||||
verbose_name = '银行账户'
|
||||
verbose_name_plural = '银行账户'
|
||||
|
||||
|
||||
class ProductCategory(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=100, verbose_name='类别名称')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='类别描述')
|
||||
product_prefix = models.CharField(max_length=5, verbose_name='产品编号前缀')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '产品类别'
|
||||
verbose_name_plural = '产品类别'
|
||||
|
||||
|
||||
class Product(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
category = models.ForeignKey(
|
||||
ProductCategory,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='products',
|
||||
verbose_name='产品类别',
|
||||
)
|
||||
name = models.CharField(max_length=100, verbose_name='产品名')
|
||||
human_id = models.CharField(max_length=100, verbose_name='产品编号', blank=True)
|
||||
color = models.CharField(max_length=50, blank=True, null=True, verbose_name='颜色')
|
||||
width_size = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True, verbose_name='宽幅')
|
||||
single_price_in = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=2,
|
||||
verbose_name='参考进价',
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
single_price_out = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=2,
|
||||
verbose_name='参考售价',
|
||||
blank=True,
|
||||
null=True,
|
||||
)
|
||||
spec = models.CharField(max_length=100, blank=True, null=True, verbose_name='规格')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
transform_rate = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=4,
|
||||
blank=True,
|
||||
null=True,
|
||||
verbose_name='公斤转换率',
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def save(
|
||||
self,
|
||||
*args,
|
||||
force_insert=False,
|
||||
force_update=False,
|
||||
using=None,
|
||||
update_fields=None,
|
||||
):
|
||||
super().save(
|
||||
*args,
|
||||
force_insert=force_insert,
|
||||
force_update=force_update,
|
||||
using=using,
|
||||
update_fields=update_fields,
|
||||
)
|
||||
# Generate human_id if not set after saving to get the ID
|
||||
if not self.human_id and self.category:
|
||||
self.human_id = f'{self.category.product_prefix}{self.id:05d}'
|
||||
super().save(
|
||||
*args,
|
||||
force_insert=False,
|
||||
force_update=False,
|
||||
using=using,
|
||||
update_fields=['human_id'],
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = '产品资料'
|
||||
verbose_name_plural = '产品资料'
|
||||
|
||||
|
||||
class Customer(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=100, verbose_name='客户名称')
|
||||
mobile = models.CharField(max_length=20, verbose_name='手机')
|
||||
area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
|
||||
email = models.EmailField(blank=True, null=True, verbose_name='电子邮箱')
|
||||
contact = models.CharField(blank=True, null=True, verbose_name='联系人')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '客户资料'
|
||||
verbose_name_plural = '客户资料'
|
||||
|
||||
|
||||
class EmployeeTypeEnum(models.TextChoices):
|
||||
PRINTER = '打纸', '打纸'
|
||||
ROLLING = '滚筒', '滚筒'
|
||||
WARE = '仓库', '仓库'
|
||||
DELIVERY = '送货', '送货'
|
||||
|
||||
|
||||
class EmployeeStatusEnum(models.TextChoices):
|
||||
ACTIVE = '在职', '在职'
|
||||
INACTIVE = '离职', '离职'
|
||||
|
||||
|
||||
class Employee(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
sys_user = models.OneToOneField(
|
||||
User,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='employee',
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name='系统用户',
|
||||
)
|
||||
name = models.CharField(max_length=100, verbose_name='员工姓名')
|
||||
job_type = models.CharField(
|
||||
max_length=20,
|
||||
choices=EmployeeTypeEnum.choices,
|
||||
default=EmployeeTypeEnum.PRINTER,
|
||||
verbose_name='职位',
|
||||
)
|
||||
mobile = models.CharField(max_length=20, blank=True, null=True, verbose_name='手机')
|
||||
area = models.CharField(max_length=100, blank=True, null=True, verbose_name='地区')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=EmployeeStatusEnum.choices,
|
||||
default=EmployeeStatusEnum.ACTIVE,
|
||||
verbose_name='员工状态',
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '员工资料'
|
||||
verbose_name_plural = '员工资料'
|
||||
|
||||
|
||||
class DeviceStatusEnum(models.TextChoices):
|
||||
ACTIVE = '使用中', '使用中'
|
||||
INACTIVE = '停用', '停用'
|
||||
MAINTENANCE = '维修中', '维修中'
|
||||
|
||||
|
||||
class DeviceTypeEnum(models.TextChoices):
|
||||
ROLLING = '滚筒', '滚筒'
|
||||
PRINTER = '打印', '打印'
|
||||
|
||||
|
||||
class DeviceInfo(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
name = models.CharField(max_length=100, verbose_name='设备名称')
|
||||
type = models.CharField(
|
||||
max_length=20,
|
||||
choices=DeviceTypeEnum.choices,
|
||||
default=DeviceTypeEnum.ROLLING,
|
||||
verbose_name='设备类型',
|
||||
)
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=DeviceStatusEnum.choices,
|
||||
default=DeviceStatusEnum.ACTIVE,
|
||||
verbose_name='设备状态',
|
||||
)
|
||||
start_working_at = models.DateField(blank=True, null=True, verbose_name='开始服役日期')
|
||||
stop_working_at = models.DateField(blank=True, null=True, verbose_name='停止服役日期')
|
||||
is_occupied = models.BooleanField(default=False, verbose_name='是否被占用')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = '设备资料'
|
||||
verbose_name_plural = '设备资料'
|
||||
|
||||
|
||||
class VehicleTransportRecord(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
vehicle_type = models.ForeignKey(
|
||||
VehicleType,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='vehicles',
|
||||
verbose_name='车次',
|
||||
)
|
||||
driver_name = models.CharField(max_length=100, verbose_name='司机姓名')
|
||||
contact_number = models.CharField(max_length=20, blank=True, null=True, verbose_name='联系电话')
|
||||
license_plate = models.CharField(max_length=20, verbose_name='车牌号码', null=True, blank=True)
|
||||
delivery_date = models.DateField(verbose_name='送货日期')
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.vehicle_type}-{self.driver_name}-{self.delivery_date}'
|
||||
|
||||
class Meta:
|
||||
verbose_name = '司机车次'
|
||||
verbose_name_plural = '司机车次'
|
||||
3
basic_info/tests.py
Normal file
3
basic_info/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
3
basic_info/views.py
Normal file
3
basic_info/views.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
28
docker-compose.yml
Normal file
28
docker-compose.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: postgres
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: myapp
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
container_name: redis
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
0
flower/__init__.py
Normal file
0
flower/__init__.py
Normal file
16
flower/asgi.py
Normal file
16
flower/asgi.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
ASGI config for flower project.
|
||||
|
||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'flower.settings')
|
||||
|
||||
application = get_asgi_application()
|
||||
10
flower/common.py
Normal file
10
flower/common.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from django.db import models
|
||||
|
||||
|
||||
class ModelBase(models.Model):
|
||||
"""Base model with common fields."""
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
134
flower/settings.py
Normal file
134
flower/settings.py
Normal file
@@ -0,0 +1,134 @@
|
||||
"""
|
||||
Django settings for flower project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 5.2.7.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/5.2/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/5.2/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from environ import Env
|
||||
|
||||
env = Env(
|
||||
DEBUG=(bool, False),
|
||||
)
|
||||
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
# Initialize environment variables
|
||||
Env.read_env(str(BASE_DIR / '.env'))
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = env('SECRET_KEY', default='weak_secret_key_for_dev_only')
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = env('DEBUG', default=False)
|
||||
|
||||
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[])
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'simpleui',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'basic_info',
|
||||
'stock',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'flower.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
'django.template.context_processors.request',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'flower.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql',
|
||||
'NAME': env('DB_NAME'),
|
||||
'USER': env('DB_USER'),
|
||||
'PASSWORD': env('DB_PASSWORD'),
|
||||
'HOST': env('DB_HOST', default='localhost'),
|
||||
'PORT': env('DB_PORT', default='5432'),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||
},
|
||||
{
|
||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/5.2/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'zh-hans'
|
||||
TIME_ZONE = 'Asia/Shanghai'
|
||||
USE_I18N = True
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/5.2/howto/static-files/
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
|
||||
# Default primary key field type
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||
24
flower/urls.py
Normal file
24
flower/urls.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
URL configuration for flower project.
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/5.2/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Import the include() function: from django.urls import include, path
|
||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.urls import path
|
||||
from stock.views import router
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('stock/', router.urls),
|
||||
]
|
||||
16
flower/wsgi.py
Normal file
16
flower/wsgi.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
WSGI config for flower project.
|
||||
|
||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'flower.settings')
|
||||
|
||||
application = get_wsgi_application()
|
||||
22
manage.py
Executable file
22
manage.py
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'flower.settings')
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
18
pyproject.toml
Normal file
18
pyproject.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[project]
|
||||
name = "flower"
|
||||
version = "0.1.0"
|
||||
description = "Add your description here"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.14"
|
||||
dependencies = [
|
||||
"django>=5.2.7",
|
||||
"django-cors>=0.1",
|
||||
"django-environ>=0.12.0",
|
||||
"django-ninja>=1.4.5",
|
||||
"django-simpleui>=2025.6.24",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"psycopg[binary]>=3.2.12",
|
||||
]
|
||||
0
stock/__init__.py
Normal file
0
stock/__init__.py
Normal file
30
stock/admin.py
Normal file
30
stock/admin.py
Normal file
@@ -0,0 +1,30 @@
|
||||
from django.contrib import admin
|
||||
from . import models
|
||||
|
||||
|
||||
@admin.register(models.PurchaseOrder)
|
||||
class PurchaseOrderAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'supplier', 'order_date', 'total_amount')
|
||||
search_fields = ('supplier__name',)
|
||||
list_filter = ('order_date',)
|
||||
ordering = ('-order_date',)
|
||||
|
||||
|
||||
@admin.register(models.Inventory)
|
||||
class InventoryAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
'id',
|
||||
'product',
|
||||
'product_color',
|
||||
'warehouse',
|
||||
'quantity',
|
||||
'num_of_rolls',
|
||||
'minimum_quantity',
|
||||
'updated_at',
|
||||
)
|
||||
search_fields = ('product__name', 'warehouse__name')
|
||||
list_filter = ('warehouse',)
|
||||
|
||||
@admin.display(description='颜色')
|
||||
def product_color(self, obj):
|
||||
return obj.product.color
|
||||
7
stock/apps.py
Normal file
7
stock/apps.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class StockConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'stock'
|
||||
verbose_name = '库存相关'
|
||||
38
stock/migrations/0001_initial.py
Normal file
38
stock/migrations/0001_initial.py
Normal file
@@ -0,0 +1,38 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 04:08
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ProductCategory',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100, verbose_name='类别名称')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='类别描述')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Product',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100, verbose_name='产品名')),
|
||||
('human_id', models.CharField(max_length=100, verbose_name='产品编号')),
|
||||
('color', models.CharField(blank=True, max_length=50, null=True, verbose_name='颜色')),
|
||||
('width_size', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='宽幅')),
|
||||
('single_price', models.DecimalField(decimal_places=2, max_digits=10, verbose_name='单价')),
|
||||
('spec', models.CharField(blank=True, max_length=100, null=True, verbose_name='规格')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('unit', models.CharField(default='米', max_length=20, verbose_name='单位')),
|
||||
('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='products', to='stock.productcategory', verbose_name='产品类别')),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 04:10
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='product',
|
||||
options={'verbose_name': '产品资料', 'verbose_name_plural': '产品资料'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='productcategory',
|
||||
options={'verbose_name': '产品类别', 'verbose_name_plural': '产品类别'},
|
||||
),
|
||||
]
|
||||
29
stock/migrations/0003_supplier.py
Normal file
29
stock/migrations/0003_supplier.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 04:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0002_alter_product_options_alter_productcategory_options'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Supplier',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100, verbose_name='供应商名称')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='电子邮箱')),
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('contact', models.TextField(blank=True, null=True, verbose_name='联系人')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '供应商',
|
||||
'verbose_name_plural': '供应商',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,43 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 04:24
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0003_supplier'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='id',
|
||||
field=models.BigAutoField(primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='productcategory',
|
||||
name='id',
|
||||
field=models.BigAutoField(primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='supplier',
|
||||
name='id',
|
||||
field=models.BigAutoField(primary_key=True, serialize=False),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PurchaseOrder',
|
||||
fields=[
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('order_date', models.DateField(verbose_name='订单日期')),
|
||||
('total_amount', models.DecimalField(decimal_places=2, max_digits=15, verbose_name='总金额')),
|
||||
('remarks', models.TextField(blank=True, null=True, verbose_name='备注')),
|
||||
('supplier', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='purchase_orders', to='stock.supplier', verbose_name='供应商')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '采购单',
|
||||
'verbose_name_plural': '采购单',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,58 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 04:29
|
||||
|
||||
import django.utils.timezone
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0004_alter_product_id_alter_productcategory_id_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='创建时间'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='product',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True, verbose_name='更新时间'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='productcategory',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='创建时间'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='productcategory',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True, verbose_name='更新时间'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='purchaseorder',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='创建时间'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='purchaseorder',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True, verbose_name='更新时间'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='supplier',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now, verbose_name='创建时间'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='supplier',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True, verbose_name='更新时间'),
|
||||
),
|
||||
]
|
||||
29
stock/migrations/0006_bankaccount.py
Normal file
29
stock/migrations/0006_bankaccount.py
Normal file
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 04:32
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0005_product_created_at_product_updated_at_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BankAccount',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='名称')),
|
||||
('auto_number', models.CharField(max_length=50, verbose_name='自动编号')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('attachment', models.FileField(blank=True, null=True, upload_to='bank_accounts/', verbose_name='附件')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '银行账户',
|
||||
'verbose_name_plural': '银行账户',
|
||||
},
|
||||
),
|
||||
]
|
||||
18
stock/migrations/0007_productcategory_product_prefix.py
Normal file
18
stock/migrations/0007_productcategory_product_prefix.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 05:07
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0006_bankaccount'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='productcategory',
|
||||
name='product_prefix',
|
||||
field=models.CharField(blank=True, max_length=5, null=True, verbose_name='产品编号前缀'),
|
||||
),
|
||||
]
|
||||
23
stock/migrations/0008_alter_product_human_id_and_more.py
Normal file
23
stock/migrations/0008_alter_product_human_id_and_more.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 05:13
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0007_productcategory_product_prefix'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='human_id',
|
||||
field=models.CharField(blank=True, max_length=100, verbose_name='产品编号'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='productcategory',
|
||||
name='product_prefix',
|
||||
field=models.CharField(max_length=5, verbose_name='产品编号前缀'),
|
||||
),
|
||||
]
|
||||
18
stock/migrations/0009_alter_product_single_price.py
Normal file
18
stock/migrations/0009_alter_product_single_price.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 05:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0008_alter_product_human_id_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='single_price',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='单价'),
|
||||
),
|
||||
]
|
||||
27
stock/migrations/0010_prodictunit.py
Normal file
27
stock/migrations/0010_prodictunit.py
Normal file
@@ -0,0 +1,27 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 05:28
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0009_alter_product_single_price'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='ProdictUnit',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=20, verbose_name='单位名称')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '产品单位',
|
||||
'verbose_name_plural': '产品单位',
|
||||
},
|
||||
),
|
||||
]
|
||||
19
stock/migrations/0011_alter_product_unit.py
Normal file
19
stock/migrations/0011_alter_product_unit.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 05:28
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0010_prodictunit'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='unit',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='stock.prodictunit', verbose_name='单位'),
|
||||
),
|
||||
]
|
||||
17
stock/migrations/0012_rename_prodictunit_productunit.py
Normal file
17
stock/migrations/0012_rename_prodictunit_productunit.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 05:34
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0011_alter_product_unit'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name='ProdictUnit',
|
||||
new_name='ProductUnit',
|
||||
),
|
||||
]
|
||||
31
stock/migrations/0013_warehouse.py
Normal file
31
stock/migrations/0013_warehouse.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 05:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0012_rename_prodictunit_productunit'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='WareHouse',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('name', models.CharField(max_length=100, verbose_name='仓库名称')),
|
||||
('location', models.CharField(blank=True, max_length=200, null=True, verbose_name='仓库地址')),
|
||||
('contact', models.CharField(blank=True, max_length=100, null=True, verbose_name='联系人')),
|
||||
('mobile', models.CharField(blank=True, max_length=20, null=True, verbose_name='手机')),
|
||||
('area', models.CharField(blank=True, max_length=100, null=True, verbose_name='地区')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '仓库资料',
|
||||
'verbose_name_plural': '仓库资料',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,46 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:06
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0013_warehouse'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='BankAccount',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='product',
|
||||
name='category',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='product',
|
||||
name='unit',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='purchaseorder',
|
||||
name='supplier',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='WareHouse',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='ProductCategory',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Product',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='ProductUnit',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='PurchaseOrder',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Supplier',
|
||||
),
|
||||
]
|
||||
33
stock/migrations/0015_initial.py
Normal file
33
stock/migrations/0015_initial.py
Normal file
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 06:11
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0002_delete_purchaseorder'),
|
||||
('stock', '0014_delete_bankaccount_remove_product_category_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='PurchaseOrder',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('order_date', models.DateField(verbose_name='订单日期')),
|
||||
('total_amount', models.DecimalField(decimal_places=2, max_digits=15, verbose_name='总金额')),
|
||||
('remarks', models.TextField(blank=True, null=True, verbose_name='备注')),
|
||||
('supplier', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='purchase_orders', to='basic_info.supplier', verbose_name='供应商')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '采购单',
|
||||
'verbose_name_plural': '采购单',
|
||||
},
|
||||
),
|
||||
]
|
||||
34
stock/migrations/0016_inventory.py
Normal file
34
stock/migrations/0016_inventory.py
Normal file
@@ -0,0 +1,34 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 07:47
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('basic_info', '0011_vehicletype_alter_deviceinfo_options_and_more'),
|
||||
('stock', '0015_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Inventory',
|
||||
fields=[
|
||||
('created_at', models.DateTimeField(auto_now_add=True, verbose_name='创建时间')),
|
||||
('updated_at', models.DateTimeField(auto_now=True, verbose_name='更新时间')),
|
||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||
('quantity', models.IntegerField(verbose_name='数量')),
|
||||
('minimum_quantity', models.IntegerField(blank=True, null=True, verbose_name='最低库存量')),
|
||||
('spec', models.CharField(blank=True, max_length=100, null=True, verbose_name='规格')),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='备注描述')),
|
||||
('product', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='inventories', to='basic_info.product', verbose_name='产品')),
|
||||
('unit', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='inventories', to='basic_info.productunit', verbose_name='单位')),
|
||||
('warehouse', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='inventories', to='basic_info.warehouse', verbose_name='仓库')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '库存',
|
||||
'verbose_name_plural': '库存',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 08:01
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0016_inventory'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='inventory',
|
||||
name='num_of_rolls',
|
||||
field=models.IntegerField(blank=True, null=True, verbose_name='匹数'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventory',
|
||||
name='quantity',
|
||||
field=models.IntegerField(verbose_name='库存数量'),
|
||||
),
|
||||
]
|
||||
17
stock/migrations/0018_remove_inventory_unit.py
Normal file
17
stock/migrations/0018_remove_inventory_unit.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-03 09:10
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0017_inventory_num_of_rolls_alter_inventory_quantity'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='inventory',
|
||||
name='unit',
|
||||
),
|
||||
]
|
||||
0
stock/migrations/__init__.py
Normal file
0
stock/migrations/__init__.py
Normal file
46
stock/models.py
Normal file
46
stock/models.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from django.db import models
|
||||
from flower.common import ModelBase
|
||||
from basic_info import models as basic_info_models
|
||||
|
||||
|
||||
class PurchaseOrder(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
supplier = models.ForeignKey(basic_info_models.Supplier, on_delete=models.PROTECT, related_name='purchase_orders', verbose_name='供应商')
|
||||
order_date = models.DateField(verbose_name='订单日期')
|
||||
total_amount = models.DecimalField(max_digits=15, decimal_places=2, verbose_name='总金额')
|
||||
remarks = models.TextField(blank=True, null=True, verbose_name='备注')
|
||||
|
||||
def __str__(self):
|
||||
return f'采购订单 {self.id} - {self.supplier.name}'
|
||||
|
||||
class Meta:
|
||||
verbose_name = '采购单'
|
||||
verbose_name_plural = '采购单'
|
||||
|
||||
|
||||
class Inventory(ModelBase):
|
||||
id = models.BigAutoField(primary_key=True)
|
||||
product = models.ForeignKey(
|
||||
basic_info_models.Product,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='inventories',
|
||||
verbose_name='产品',
|
||||
)
|
||||
warehouse = models.ForeignKey(
|
||||
basic_info_models.WareHouse,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='inventories',
|
||||
verbose_name='仓库',
|
||||
)
|
||||
quantity = models.IntegerField(verbose_name='库存数量')
|
||||
num_of_rolls = models.IntegerField(null=True, blank=True, verbose_name='匹数')
|
||||
minimum_quantity = models.IntegerField(null=True, blank=True, verbose_name='最低库存量')
|
||||
spec = models.CharField(max_length=100, blank=True, null=True, verbose_name='规格')
|
||||
description = models.TextField(blank=True, null=True, verbose_name='备注描述')
|
||||
|
||||
def __str__(self):
|
||||
return f'库存 {self.product.name} - 仓库: {self.warehouse.name}'
|
||||
|
||||
class Meta:
|
||||
verbose_name = '库存'
|
||||
verbose_name_plural = '库存'
|
||||
3
stock/tests.py
Normal file
3
stock/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
9
stock/views.py
Normal file
9
stock/views.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from ninja import NinjaAPI
|
||||
|
||||
|
||||
router = NinjaAPI()
|
||||
|
||||
|
||||
@router.get('/')
|
||||
async def index(request):
|
||||
return {'message': 'Welcome to the Stock API'}
|
||||
218
uv.lock
generated
Normal file
218
uv.lock
generated
Normal file
@@ -0,0 +1,218 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.14"
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
version = "0.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "asgiref"
|
||||
version = "3.10.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/46/08/4dfec9b90758a59acc6be32ac82e98d1fbfc321cb5cfa410436dbacf821c/asgiref-3.10.0.tar.gz", hash = "sha256:d89f2d8cd8b56dada7d52fa7dc8075baa08fb836560710d38c292a7a3f78c04e", size = 37483, upload-time = "2025-10-05T09:15:06.557Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/17/9c/fc2331f538fbf7eedba64b2052e99ccf9ba9d6888e2f41441ee28847004b/asgiref-3.10.0-py3-none-any.whl", hash = "sha256:aef8a81283a34d0ab31630c9b7dfe70c812c95eba78171367ca8745e88124734", size = 24050, upload-time = "2025-10-05T09:15:05.11Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django"
|
||||
version = "5.2.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "asgiref" },
|
||||
{ name = "sqlparse" },
|
||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/96/bd84e2bb997994de8bcda47ae4560991084e86536541d7214393880f01a8/django-5.2.7.tar.gz", hash = "sha256:e0f6f12e2551b1716a95a63a1366ca91bbcd7be059862c1b18f989b1da356cdd", size = 10865812, upload-time = "2025-10-01T14:22:12.081Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8f/ef/81f3372b5dd35d8d354321155d1a38894b2b766f576d0abffac4d8ae78d9/django-5.2.7-py3-none-any.whl", hash = "sha256:59a13a6515f787dec9d97a0438cd2efac78c8aca1c80025244b0fe507fe0754b", size = 8307145, upload-time = "2025-10-01T14:22:49.476Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-cors"
|
||||
version = "0.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b6/94/59b5353380df1aacd28e1efc1e77ce9925f65ef9adab6c44238daa9cefa3/django-cors-0.1.tar.gz", hash = "sha256:ba31c9455ddb848e578b26bac3634049951149775b818a35476d2b50350640c3", size = 1066, upload-time = "2012-12-04T02:52:05.092Z" }
|
||||
|
||||
[[package]]
|
||||
name = "django-environ"
|
||||
version = "0.12.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d6/04/65d2521842c42f4716225f20d8443a50804920606aec018188bbee30a6b0/django_environ-0.12.0.tar.gz", hash = "sha256:227dc891453dd5bde769c3449cf4a74b6f2ee8f7ab2361c93a07068f4179041a", size = 56804, upload-time = "2025-01-13T17:03:37.74Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/83/b3/0a3bec4ecbfee960f39b1842c2f91e4754251e0a6ed443db9fe3f666ba8f/django_environ-0.12.0-py2.py3-none-any.whl", hash = "sha256:92fb346a158abda07ffe6eb23135ce92843af06ecf8753f43adf9d2366dcc0ca", size = 19957, upload-time = "2025-01-13T17:03:32.918Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-ninja"
|
||||
version = "1.4.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
{ name = "pydantic" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/fa/9a/558489e0e25173772fbd826306b7d1777e80285b02d69e0e1aaec41e3eec/django_ninja-1.4.5.tar.gz", hash = "sha256:aa1a2ee2b22c5f1c2f4bfbc004386be7074cbfaf133680c2b359a31221965503", size = 3710511, upload-time = "2025-10-19T18:28:02.362Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/49/e3/168274a8def4b9a2fb2540319a68914e8e4e529cd7f7b5f1ba8939d011bc/django_ninja-1.4.5-py3-none-any.whl", hash = "sha256:d779702ddc6e17b10739049ddb075a6a1e6c6270bdc04e0b0429f6adbf670373", size = 2426449, upload-time = "2025-10-19T18:28:00.518Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-simpleui"
|
||||
version = "2025.6.24"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/97/d7/57ac337258399c33c28b5d960407e2c640f22a2edabf2e894d1b51e25fee/django-simpleui-2025.6.24.tar.gz", hash = "sha256:95d1224454a0531071ec7fcd1c6f57acf90e85160c72d6b1d23d538c3a92f4ed", size = 6483918, upload-time = "2025-06-24T06:35:27.545Z" }
|
||||
|
||||
[[package]]
|
||||
name = "flower"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
{ name = "django-cors" },
|
||||
{ name = "django-environ" },
|
||||
{ name = "django-ninja" },
|
||||
{ name = "django-simpleui" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "psycopg", extra = ["binary"] },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "django", specifier = ">=5.2.7" },
|
||||
{ name = "django-cors", specifier = ">=0.1" },
|
||||
{ name = "django-environ", specifier = ">=0.12.0" },
|
||||
{ name = "django-ninja", specifier = ">=1.4.5" },
|
||||
{ name = "django-simpleui", specifier = ">=2025.6.24" },
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [{ name = "psycopg", extras = ["binary"], specifier = ">=3.2.12" }]
|
||||
|
||||
[[package]]
|
||||
name = "psycopg"
|
||||
version = "3.2.12"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a8/77/c72d10262b872617e509a0c60445afcc4ce2cd5cd6bc1c97700246d69c85/psycopg-3.2.12.tar.gz", hash = "sha256:85c08d6f6e2a897b16280e0ff6406bef29b1327c045db06d21f364d7cd5da90b", size = 160642, upload-time = "2025-10-26T00:46:03.045Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c8/28/8c4f90e415411dc9c78d6ba10b549baa324659907c13f64bfe3779d4066c/psycopg-3.2.12-py3-none-any.whl", hash = "sha256:8a1611a2d4c16ae37eada46438be9029a35bb959bb50b3d0e1e93c0f3d54c9ee", size = 206765, upload-time = "2025-10-26T00:10:42.173Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
binary = [
|
||||
{ name = "psycopg-binary", marker = "implementation_name != 'pypy'" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "psycopg-binary"
|
||||
version = "3.2.12"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/5b/76fbb40b981b73b285a00dccafc38cf67b7a9b3f7d4f2025dda7b896e7ef/psycopg_binary-3.2.12-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:dc68094e00a5a7e8c20de1d3a0d5e404a27f522e18f8eb62bbbc9f865c3c81ef", size = 4016868, upload-time = "2025-10-26T00:31:29.974Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/08/8841ae3e2d1a3228e79eaaf5b7f991d15f0a231bb5031a114305b19724b1/psycopg_binary-3.2.12-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2d55009eeddbef54c711093c986daaf361d2c4210aaa1ee905075a3b97a62441", size = 4090508, upload-time = "2025-10-26T00:32:04.192Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/de/a41f62230cf4095ae4547eceada218cf28c17e7f94376913c1c8dde9546f/psycopg_binary-3.2.12-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:66a031f22e4418016990446d3e38143826f03ad811b9f78f58e2afbc1d343f7a", size = 4629788, upload-time = "2025-10-26T00:32:43.28Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/45/19/529d92134eae44475f781a86d58cdf3edd0953e17c69762abf387a9f2636/psycopg_binary-3.2.12-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:58ed30d33c25d7dc8d2f06285e88493147c2a660cc94713e4b563a99efb80a1f", size = 4724124, upload-time = "2025-10-26T00:33:22.594Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/f5/97344e87065f7c9713ce213a2cff7732936ec3af6622e4b2a88715a953f2/psycopg_binary-3.2.12-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e0b5ccd03ca4749b8f66f38608ccbcb415cbd130d02de5eda80d042b83bee90e", size = 4411340, upload-time = "2025-10-26T00:34:00.759Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/c2/34bce068f6bfb4c2e7bb1187bb64a3f3be254702b158c4ad05eacc0055cf/psycopg_binary-3.2.12-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:909de94de7dd4d6086098a5755562207114c9638ec42c52d84c8a440c45fe084", size = 3867815, upload-time = "2025-10-26T00:34:33.181Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/a1/c647e01ab162e6bfa52380e23e486215e9d28ffd31e9cf3cb1e9ca59008b/psycopg_binary-3.2.12-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:7130effd0517881f3a852eff98729d51034128f0737f64f0d1c7ea8343d77bd7", size = 3541756, upload-time = "2025-10-26T00:35:08.622Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/d0/795bdaa8c946a7b7126bf7ca8d4371eaaa613093e3ec341a0e50f52cbee2/psycopg_binary-3.2.12-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:89b3c5201ca616d69ca0c3c0003ca18f7170a679c445c7e386ebfb4f29aa738e", size = 3587950, upload-time = "2025-10-26T00:35:41.183Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/cf/10c3e95827a3ca8af332dfc471befec86e15a14dc83cee893c49a4910dad/psycopg_binary-3.2.12-cp314-cp314-win_amd64.whl", hash = "sha256:48a8e29f3e38fcf8d393b8fe460d83e39c107ad7e5e61cd3858a7569e0554a39", size = 3005787, upload-time = "2025-10-26T00:36:06.783Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.12.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "annotated-types" },
|
||||
{ name = "pydantic-core" },
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "typing-inspection" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/1e/4f0a3233767010308f2fd6bd0814597e3f63f1dc98304a9112b8759df4ff/pydantic-2.12.3.tar.gz", hash = "sha256:1da1c82b0fc140bb0103bc1441ffe062154c8d38491189751ee00fd8ca65ce74", size = 819383, upload-time = "2025-10-17T15:04:21.222Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a1/6b/83661fa77dcefa195ad5f8cd9af3d1a7450fd57cc883ad04d65446ac2029/pydantic-2.12.3-py3-none-any.whl", hash = "sha256:6986454a854bc3bc6e5443e1369e06a3a456af9d339eda45510f517d9ea5c6bf", size = 462431, upload-time = "2025-10-17T15:04:19.346Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.41.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/df/18/d0944e8eaaa3efd0a91b0f1fc537d3be55ad35091b6a87638211ba691964/pydantic_core-2.41.4.tar.gz", hash = "sha256:70e47929a9d4a1905a67e4b687d5946026390568a8e952b92824118063cee4d5", size = 457557, upload-time = "2025-10-14T10:23:47.909Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/54/28/d3325da57d413b9819365546eb9a6e8b7cbd9373d9380efd5f74326143e6/pydantic_core-2.41.4-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:e9205d97ed08a82ebb9a307e92914bb30e18cdf6f6b12ca4bedadb1588a0bfe1", size = 2102022, upload-time = "2025-10-14T10:21:32.809Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/24/b58a1bc0d834bf1acc4361e61233ee217169a42efbdc15a60296e13ce438/pydantic_core-2.41.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:82df1f432b37d832709fbcc0e24394bba04a01b6ecf1ee87578145c19cde12ac", size = 1905495, upload-time = "2025-10-14T10:21:34.812Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/a4/71f759cc41b7043e8ecdaab81b985a9b6cad7cec077e0b92cff8b71ecf6b/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3b4cc4539e055cfa39a3763c939f9d409eb40e85813257dcd761985a108554", size = 1956131, upload-time = "2025-10-14T10:21:36.924Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/64/1e79ac7aa51f1eec7c4cda8cbe456d5d09f05fdd68b32776d72168d54275/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b1eb1754fce47c63d2ff57fdb88c351a6c0150995890088b33767a10218eaa4e", size = 2052236, upload-time = "2025-10-14T10:21:38.927Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/e3/a3ffc363bd4287b80f1d43dc1c28ba64831f8dfc237d6fec8f2661138d48/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e6ab5ab30ef325b443f379ddb575a34969c333004fca5a1daa0133a6ffaad616", size = 2223573, upload-time = "2025-10-14T10:21:41.574Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/28/27/78814089b4d2e684a9088ede3790763c64693c3d1408ddc0a248bc789126/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:31a41030b1d9ca497634092b46481b937ff9397a86f9f51bd41c4767b6fc04af", size = 2342467, upload-time = "2025-10-14T10:21:44.018Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/92/97/4de0e2a1159cb85ad737e03306717637842c88c7fd6d97973172fb183149/pydantic_core-2.41.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a44ac1738591472c3d020f61c6df1e4015180d6262ebd39bf2aeb52571b60f12", size = 2063754, upload-time = "2025-10-14T10:21:46.466Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/50/8cb90ce4b9efcf7ae78130afeb99fd1c86125ccdf9906ef64b9d42f37c25/pydantic_core-2.41.4-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d72f2b5e6e82ab8f94ea7d0d42f83c487dc159c5240d8f83beae684472864e2d", size = 2196754, upload-time = "2025-10-14T10:21:48.486Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/34/3b/ccdc77af9cd5082723574a1cc1bcae7a6acacc829d7c0a06201f7886a109/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:c4d1e854aaf044487d31143f541f7aafe7b482ae72a022c664b2de2e466ed0ad", size = 2137115, upload-time = "2025-10-14T10:21:50.63Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/ba/e7c7a02651a8f7c52dc2cff2b64a30c313e3b57c7d93703cecea76c09b71/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:b568af94267729d76e6ee5ececda4e283d07bbb28e8148bb17adad93d025d25a", size = 2317400, upload-time = "2025-10-14T10:21:52.959Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/ba/6c533a4ee8aec6b812c643c49bb3bd88d3f01e3cebe451bb85512d37f00f/pydantic_core-2.41.4-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:6d55fb8b1e8929b341cc313a81a26e0d48aa3b519c1dbaadec3a6a2b4fcad025", size = 2312070, upload-time = "2025-10-14T10:21:55.419Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/22/ae/f10524fcc0ab8d7f96cf9a74c880243576fd3e72bd8ce4f81e43d22bcab7/pydantic_core-2.41.4-cp314-cp314-win32.whl", hash = "sha256:5b66584e549e2e32a1398df11da2e0a7eff45d5c2d9db9d5667c5e6ac764d77e", size = 1982277, upload-time = "2025-10-14T10:21:57.474Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/dc/e5aa27aea1ad4638f0c3fb41132f7eb583bd7420ee63204e2d4333a3bbf9/pydantic_core-2.41.4-cp314-cp314-win_amd64.whl", hash = "sha256:557a0aab88664cc552285316809cab897716a372afaf8efdbef756f8b890e894", size = 2024608, upload-time = "2025-10-14T10:21:59.557Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3e/61/51d89cc2612bd147198e120a13f150afbf0bcb4615cddb049ab10b81b79e/pydantic_core-2.41.4-cp314-cp314-win_arm64.whl", hash = "sha256:3f1ea6f48a045745d0d9f325989d8abd3f1eaf47dd00485912d1a3a63c623a8d", size = 1967614, upload-time = "2025-10-14T10:22:01.847Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0d/c2/472f2e31b95eff099961fa050c376ab7156a81da194f9edb9f710f68787b/pydantic_core-2.41.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6c1fe4c5404c448b13188dd8bd2ebc2bdd7e6727fa61ff481bcc2cca894018da", size = 1876904, upload-time = "2025-10-14T10:22:04.062Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4a/07/ea8eeb91173807ecdae4f4a5f4b150a520085b35454350fc219ba79e66a3/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:523e7da4d43b113bf8e7b49fa4ec0c35bf4fe66b2230bfc5c13cc498f12c6c3e", size = 1882538, upload-time = "2025-10-14T10:22:06.39Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/29/b53a9ca6cd366bfc928823679c6a76c7a4c69f8201c0ba7903ad18ebae2f/pydantic_core-2.41.4-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5729225de81fb65b70fdb1907fcf08c75d498f4a6f15af005aabb1fdadc19dfa", size = 2041183, upload-time = "2025-10-14T10:22:08.812Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/3d/f8c1a371ceebcaf94d6dd2d77c6cf4b1c078e13a5837aee83f760b4f7cfd/pydantic_core-2.41.4-cp314-cp314t-win_amd64.whl", hash = "sha256:de2cfbb09e88f0f795fd90cf955858fc2c691df65b1f21f0aa00b99f3fbc661d", size = 1993542, upload-time = "2025-10-14T10:22:11.332Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8a/ac/9fc61b4f9d079482a290afe8d206b8f490e9fd32d4fc03ed4fc698214e01/pydantic_core-2.41.4-cp314-cp314t-win_arm64.whl", hash = "sha256:d34f950ae05a83e0ede899c595f312ca976023ea1db100cd5aa188f7005e3ab0", size = 1973897, upload-time = "2025-10-14T10:22:13.444Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlparse"
|
||||
version = "0.5.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e5/40/edede8dd6977b0d3da179a342c198ed100dd2aba4be081861ee5911e4da4/sqlparse-0.5.3.tar.gz", hash = "sha256:09f67787f56a0b16ecdbde1bfc7f5d9c3371ca683cfeaa8e6ff60b4807ec9272", size = 84999, upload-time = "2024-12-10T12:05:30.728Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/a9/5c/bfd6bd0bf979426d405cc6e71eceb8701b148b16c21d2dc3c261efc61c7b/sqlparse-0.5.3-py3-none-any.whl", hash = "sha256:cf2196ed3418f3ba5de6af7e82c694a9fbdbfecccdfc72e281548517081f16ca", size = 44415, upload-time = "2024-12-10T12:05:27.824Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typing-inspection"
|
||||
version = "0.4.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2025.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" },
|
||||
]
|
||||
Reference in New Issue
Block a user