在庫管理機能 Phase 1 実装(apps/materials + フロントエンド)
Backend: - apps/materials 新規作成(Material, FertilizerProfile, PesticideProfile, StockTransaction) - 資材マスタ CRUD API(/api/materials/materials/) - 入出庫履歴 API(/api/materials/stock-transactions/) - 在庫集計 API(/api/materials/stock-summary/) - 既存 Fertilizer に material OneToOneField 追加(0005マイグレーション、データ移行込み) Frontend: - /materials: 在庫一覧画面(タブフィルタ、履歴展開、入出庫モーダル) - /materials/masters: 資材マスタ管理(肥料/農薬/その他タブ、インライン編集) - Navbar に「在庫管理」メニュー追加 - Material/StockTransaction/StockSummary 型定義追加 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
87
backend/apps/materials/migrations/0001_initial.py
Normal file
87
backend/apps/materials/migrations/0001_initial.py
Normal file
@@ -0,0 +1,87 @@
|
||||
import decimal
|
||||
|
||||
import django.core.validators
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = []
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Material',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100, verbose_name='資材名')),
|
||||
('material_type', models.CharField(choices=[('fertilizer', '肥料'), ('pesticide', '農薬'), ('seedling', '種苗'), ('other', 'その他')], max_length=20, verbose_name='資材種別')),
|
||||
('maker', models.CharField(blank=True, default='', max_length=100, verbose_name='メーカー')),
|
||||
('stock_unit', models.CharField(choices=[('bag', '袋'), ('bottle', '本'), ('kg', 'kg'), ('liter', 'L'), ('piece', '個')], default='bag', max_length=20, verbose_name='在庫単位')),
|
||||
('is_active', models.BooleanField(default=True, verbose_name='使用中')),
|
||||
('notes', models.TextField(blank=True, default='', verbose_name='備考')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('updated_at', models.DateTimeField(auto_now=True)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '資材',
|
||||
'verbose_name_plural': '資材',
|
||||
'ordering': ['material_type', 'name'],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='FertilizerProfile',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('capacity_kg', models.DecimalField(blank=True, decimal_places=3, max_digits=8, null=True, verbose_name='1袋重量(kg)')),
|
||||
('nitrogen_pct', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True, verbose_name='窒素(%)')),
|
||||
('phosphorus_pct', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True, verbose_name='リン酸(%)')),
|
||||
('potassium_pct', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True, verbose_name='カリ(%)')),
|
||||
('material', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='fertilizer_profile', to='materials.material')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '肥料詳細',
|
||||
'verbose_name_plural': '肥料詳細',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PesticideProfile',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('registration_no', models.CharField(blank=True, default='', max_length=100, verbose_name='農薬登録番号')),
|
||||
('formulation', models.CharField(blank=True, default='', max_length=100, verbose_name='剤型')),
|
||||
('usage_unit', models.CharField(blank=True, default='', max_length=50, verbose_name='使用単位')),
|
||||
('dilution_ratio', models.CharField(blank=True, default='', max_length=100, verbose_name='希釈倍率')),
|
||||
('active_ingredient', models.CharField(blank=True, default='', max_length=200, verbose_name='有効成分')),
|
||||
('category', models.CharField(blank=True, default='', max_length=100, verbose_name='分類')),
|
||||
('material', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='pesticide_profile', to='materials.material')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '農薬詳細',
|
||||
'verbose_name_plural': '農薬詳細',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='StockTransaction',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('transaction_type', models.CharField(choices=[('purchase', '入庫'), ('use', '使用'), ('adjustment_plus', '棚卸増'), ('adjustment_minus', '棚卸減'), ('discard', '廃棄')], max_length=30, verbose_name='取引種別')),
|
||||
('quantity', models.DecimalField(decimal_places=3, max_digits=10, validators=[django.core.validators.MinValueValidator(decimal.Decimal('0.001'))], verbose_name='数量')),
|
||||
('occurred_on', models.DateField(verbose_name='発生日')),
|
||||
('note', models.TextField(blank=True, default='', verbose_name='備考')),
|
||||
('created_at', models.DateTimeField(auto_now_add=True)),
|
||||
('material', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='stock_transactions', to='materials.material', verbose_name='資材')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': '入出庫履歴',
|
||||
'verbose_name_plural': '入出庫履歴',
|
||||
'ordering': ['-occurred_on', '-created_at', '-id'],
|
||||
},
|
||||
),
|
||||
migrations.AddConstraint(
|
||||
model_name='material',
|
||||
constraint=models.UniqueConstraint(fields=('material_type', 'name'), name='uniq_material_type_name'),
|
||||
),
|
||||
]
|
||||
1
backend/apps/materials/migrations/__init__.py
Normal file
1
backend/apps/materials/migrations/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user