From 3869ac6ad732e04c271e03282f2cb8e6c25ddc67 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 16 Feb 2026 09:47:36 +0000 Subject: [PATCH] Add comprehensive ERP system using Django Implemented a full-featured ERP system with the following modules: - Core: Dashboard and Company Info - HR: Employee, Department, and Position management - Sales: Customer, Product, Order, and OrderItem management - Inventory: Stock and StockMovement management with auto-update logic Features: - Customized Django Admin for easy data entry and management - Dashboard with key metrics (Order count, Low stock alerts) - Initial data population script - Japanese localization Co-authored-by: muumuu8181 <87556753+muumuu8181@users.noreply.github.com> --- .gitignore | 121 ++++++++++ README_ERP.md | 64 ++++++ core/__init__.py | 0 core/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 118 bytes core/__pycache__/admin.cpython-312.pyc | Bin 0 -> 563 bytes core/__pycache__/apps.cpython-312.pyc | Bin 0 -> 359 bytes core/__pycache__/models.cpython-312.pyc | Bin 0 -> 1551 bytes core/__pycache__/views.cpython-312.pyc | Bin 0 -> 719 bytes core/admin.py | 6 + core/apps.py | 5 + core/migrations/0001_initial.py | 65 ++++++ core/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-312.pyc | Bin 0 -> 1699 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 129 bytes core/models.py | 17 ++ core/templates/core/index.html | 94 ++++++++ core/tests.py | 3 + core/views.py | 14 ++ db.sqlite3 | Bin 0 -> 229376 bytes erp_system/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 124 bytes .../__pycache__/settings.cpython-312.pyc | Bin 0 -> 2437 bytes erp_system/__pycache__/tests.cpython-312.pyc | Bin 0 -> 3464 bytes erp_system/__pycache__/urls.cpython-312.pyc | Bin 0 -> 1107 bytes erp_system/__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 618 bytes erp_system/asgi.py | 16 ++ erp_system/settings.py | 121 ++++++++++ erp_system/tests.py | 40 ++++ erp_system/urls.py | 25 +++ erp_system/verification/dashboard.png | Bin 0 -> 75295 bytes erp_system/verification/verify_dashboard.py | 25 +++ erp_system/wsgi.py | 16 ++ hello.py | 37 ++-- hello_0718.py | 3 +- hr/__init__.py | 0 hr/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 116 bytes hr/__pycache__/admin.cpython-312.pyc | Bin 0 -> 1398 bytes hr/__pycache__/apps.cpython-312.pyc | Bin 0 -> 353 bytes hr/__pycache__/models.cpython-312.pyc | Bin 0 -> 3390 bytes hr/admin.py | 19 ++ hr/apps.py | 5 + hr/migrations/0001_initial.py | 125 +++++++++++ hr/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-312.pyc | Bin 0 -> 3153 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 127 bytes hr/models.py | 42 ++++ hr/tests.py | 3 + hr/views.py | 3 + inventory/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 123 bytes inventory/__pycache__/admin.cpython-312.pyc | Bin 0 -> 1076 bytes inventory/__pycache__/apps.cpython-312.pyc | Bin 0 -> 374 bytes inventory/__pycache__/models.cpython-312.pyc | Bin 0 -> 3756 bytes inventory/admin.py | 15 ++ inventory/apps.py | 5 + inventory/migrations/0001_initial.py | 100 +++++++++ inventory/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-312.pyc | Bin 0 -> 2699 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 134 bytes inventory/models.py | 53 +++++ inventory/tests.py | 3 + inventory/views.py | 3 + manage.py | 23 ++ populate_data.py | 94 ++++++++ sales/__init__.py | 0 sales/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 119 bytes sales/__pycache__/admin.cpython-312.pyc | Bin 0 -> 1869 bytes sales/__pycache__/apps.cpython-312.pyc | Bin 0 -> 362 bytes sales/__pycache__/models.cpython-312.pyc | Bin 0 -> 6063 bytes sales/admin.py | 30 +++ sales/apps.py | 5 + sales/migrations/0001_initial.py | 206 ++++++++++++++++++ sales/migrations/__init__.py | 0 .../__pycache__/0001_initial.cpython-312.pyc | Bin 0 -> 4347 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 130 bytes sales/models.py | 83 +++++++ sales/tests.py | 3 + sales/views.py | 3 + server.log | 172 +++++++++++++++ test_hello_0718.py | 6 +- 80 files changed, 1655 insertions(+), 18 deletions(-) create mode 100644 .gitignore create mode 100644 README_ERP.md create mode 100644 core/__init__.py create mode 100644 core/__pycache__/__init__.cpython-312.pyc create mode 100644 core/__pycache__/admin.cpython-312.pyc create mode 100644 core/__pycache__/apps.cpython-312.pyc create mode 100644 core/__pycache__/models.cpython-312.pyc create mode 100644 core/__pycache__/views.cpython-312.pyc create mode 100644 core/admin.py create mode 100644 core/apps.py create mode 100644 core/migrations/0001_initial.py create mode 100644 core/migrations/__init__.py create mode 100644 core/migrations/__pycache__/0001_initial.cpython-312.pyc create mode 100644 core/migrations/__pycache__/__init__.cpython-312.pyc create mode 100644 core/models.py create mode 100644 core/templates/core/index.html create mode 100644 core/tests.py create mode 100644 core/views.py create mode 100644 db.sqlite3 create mode 100644 erp_system/__init__.py create mode 100644 erp_system/__pycache__/__init__.cpython-312.pyc create mode 100644 erp_system/__pycache__/settings.cpython-312.pyc create mode 100644 erp_system/__pycache__/tests.cpython-312.pyc create mode 100644 erp_system/__pycache__/urls.cpython-312.pyc create mode 100644 erp_system/__pycache__/wsgi.cpython-312.pyc create mode 100644 erp_system/asgi.py create mode 100644 erp_system/settings.py create mode 100644 erp_system/tests.py create mode 100644 erp_system/urls.py create mode 100644 erp_system/verification/dashboard.png create mode 100644 erp_system/verification/verify_dashboard.py create mode 100644 erp_system/wsgi.py create mode 100644 hr/__init__.py create mode 100644 hr/__pycache__/__init__.cpython-312.pyc create mode 100644 hr/__pycache__/admin.cpython-312.pyc create mode 100644 hr/__pycache__/apps.cpython-312.pyc create mode 100644 hr/__pycache__/models.cpython-312.pyc create mode 100644 hr/admin.py create mode 100644 hr/apps.py create mode 100644 hr/migrations/0001_initial.py create mode 100644 hr/migrations/__init__.py create mode 100644 hr/migrations/__pycache__/0001_initial.cpython-312.pyc create mode 100644 hr/migrations/__pycache__/__init__.cpython-312.pyc create mode 100644 hr/models.py create mode 100644 hr/tests.py create mode 100644 hr/views.py create mode 100644 inventory/__init__.py create mode 100644 inventory/__pycache__/__init__.cpython-312.pyc create mode 100644 inventory/__pycache__/admin.cpython-312.pyc create mode 100644 inventory/__pycache__/apps.cpython-312.pyc create mode 100644 inventory/__pycache__/models.cpython-312.pyc create mode 100644 inventory/admin.py create mode 100644 inventory/apps.py create mode 100644 inventory/migrations/0001_initial.py create mode 100644 inventory/migrations/__init__.py create mode 100644 inventory/migrations/__pycache__/0001_initial.cpython-312.pyc create mode 100644 inventory/migrations/__pycache__/__init__.cpython-312.pyc create mode 100644 inventory/models.py create mode 100644 inventory/tests.py create mode 100644 inventory/views.py create mode 100755 manage.py create mode 100644 populate_data.py create mode 100644 sales/__init__.py create mode 100644 sales/__pycache__/__init__.cpython-312.pyc create mode 100644 sales/__pycache__/admin.cpython-312.pyc create mode 100644 sales/__pycache__/apps.cpython-312.pyc create mode 100644 sales/__pycache__/models.cpython-312.pyc create mode 100644 sales/admin.py create mode 100644 sales/apps.py create mode 100644 sales/migrations/0001_initial.py create mode 100644 sales/migrations/__init__.py create mode 100644 sales/migrations/__pycache__/0001_initial.cpython-312.pyc create mode 100644 sales/migrations/__pycache__/__init__.cpython-312.pyc create mode 100644 sales/models.py create mode 100644 sales/tests.py create mode 100644 sales/views.py create mode 100644 server.log diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0aed9fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,121 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# verification +erp_system/verification/ diff --git a/README_ERP.md b/README_ERP.md new file mode 100644 index 0000000..38523c3 --- /dev/null +++ b/README_ERP.md @@ -0,0 +1,64 @@ +# 統合業務ERPシステム + +このシステムは、Djangoを用いて構築された、実運用を想定したERP(Enterprise Resource Planning)システムです。 +人事、販売、在庫の各管理機能を備え、すぐに業務での利用を開始できます。 + +## 主な機能 + +1. **人事管理 (HR)** + - 従業員情報の登録・管理 + - 部署・役職のマスタ管理 + - 従業員の検索・フィルタリング + +2. **販売管理 (Sales)** + - 顧客情報の管理 + - 商品マスタ管理 + - 受注管理(見積、受注、請求ステータス管理) + - 受注明細のインライン編集 + +3. **在庫管理 (Inventory)** + - 商品ごとの在庫数管理 + - 入出庫履歴(入荷、出荷、返品、廃棄)の記録 + - 在庫数の自動更新機能 + +## セットアップと起動方法 + +### 前提条件 +- Python 3.x がインストールされていること + +### インストール手順 + +1. 依存パッケージのインストール + ```bash + pip install django + ``` + +2. データベースのセットアップ + ```bash + python manage.py migrate + ``` + +3. 初期データの投入(管理者ユーザーとテストデータが作成されます) + ```bash + python populate_data.py + ``` + ※ 管理者ユーザー名: `admin` / パスワード: `adminpass` + +4. サーバーの起動 + ```bash + python manage.py runserver + ``` + +5. アクセス + - ブラウザで `http://127.0.0.1:8000/` にアクセスするとダッシュボードが表示されます。 + - 管理画面へは `http://127.0.0.1:8000/admin/` からアクセスできます。 + +## 運用上の注意 + +- **在庫の更新**: 在庫数は「入出庫履歴 (StockMovement)」を作成することで自動的に増減します。手動で在庫数を変更することも可能ですが、履歴を残すために履歴の登録を推奨します。 +- **受注の入力**: 受注画面で「受注明細」を追加することで、複数の商品を一度に注文登録できます。 + +## 開発者情報 + +- このシステムは拡張性を考慮して設計されています。 +- データベースはデフォルトでSQLiteを使用していますが、`settings.py` を変更することでPostgreSQLなどのRDBMSに容易に移行可能です。 diff --git a/core/__init__.py b/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/__pycache__/__init__.cpython-312.pyc b/core/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..05dc940f306d8160c16742b8aed0cda2b8a2803c GIT binary patch literal 118 zcmX@j%ge<81gjrU$^_AmK?FMZ%mNgd&QQsq$>_I|p@<2{`wUX^OH@Cxpg=!4zbI8d rK0Y%qvm`!Vub}c4hfQvNN@-52T@fo#6(bNAgBTx~85tRin1L(+N@5rG literal 0 HcmV?d00001 diff --git a/core/__pycache__/admin.cpython-312.pyc b/core/__pycache__/admin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66a20352fcb6ba7e521f27c102e2c0df1eb4a879 GIT binary patch literal 563 zcmYjNJ4*vW5T3csi^NA%B#p05t}&IBB8Y_u>JPYPS+i?AxtDuMah-x-8*K6$B)>xt zti(cC5Cp4q%2`>tdv_sjvGaX1-+Z&P&$F|2(C6v%-hI^Z(~!xj6d;W>7y<{59{A`W z0=GEvET1?8!2*GowMo-73Npf+S#SuvbPK$!mD#+h%AgU+`KU-cm84=<$A;Oc%8dJN zFg9MAH4Z{QVnK2goQIu4pM_!;q)knSAizNmj>XX-iDeVj{MWc|9PN@S10Oe&{#Rn75B7Ied{P8js0dnV2IsEQsg zyjYeEsY%h*Glf+36O+ys%I(eix!q!>+|3`oCtI4DPl~to^+gcz9X8%!{R8K(m+#hY f)&`ANT=}sOcL)8q*5*rVGX+gj0@mucNoTfycyokD literal 0 HcmV?d00001 diff --git a/core/__pycache__/apps.cpython-312.pyc b/core/__pycache__/apps.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76160181fe07297bcf92d4de0c92f93500955c2d GIT binary patch literal 359 zcmX@j%ge<81gjrU$_xh5k3k$5V1+V1s{t9)8B!Qh7;_kM8KW2(8JHN{8B&;97*d#1 z8CNqy)I~8>vS_lt1aUMOZ*e*n6gcPSrDdikL!==jBb4)50LYlmkjfCnn8Fanl)@Or zT*;)#e2dFDzbF-=?-olkknN|*a*HEAJ})shH9r0pSA2YKeoAQ$h|LopUs#%$1C?O` z(JL7~gUtUWsGnF+pbydxVifBYR2G3e114C2jAC{m(ZXikhzBO)2eh9%B`Yy6 zJzo!`tq9~Xh(>M@3#^bA$hyU0196325kHU%@>8)0kodsN$jEq?LGcS4Bcsp+$*&AR H3akqNbahV& literal 0 HcmV?d00001 diff --git a/core/__pycache__/models.cpython-312.pyc b/core/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d116b057d6ae64477df9a75e3d313917d42c96c GIT binary patch literal 1551 zcmaJ>O>7%Q6rNr0#(!%ku0z}4Btoi!SSciz3L%6z(4-X+jew>g8N{&3P8x^xu9@{x zj5t_!kemZbK%xE(Pz_K&?+MqSVff0g|oQje>kBDzM&>?kal~ehuufltp zr1%J)pbDy3?W?riOZNRQ*Uy-O8tCErUG6~FZU?!{U^R3YV9;d_cJ{lo%MAB0!!Gl9 zm(f9tDODqfF-0E1i&py&c~Q3r1FQ(KLtVdmWCbM$a&dXk4xcj88AZ>%q%Rr=|1e`# zkcquJU*5a=^ZxoLGH-{{$_H2@`i1P0Exk|ZykQcoD`_%kL0R_ht~FQlvOxW8VGFvY zX|_18Df+tDc*646{qmEQ(Se5 zRj2Ti?4#fYg|>6Av5qk06uxr`-#f)iPT{6gxat&3?!|j|ziO7&n;YLYzbG(&CB@1b zST`x^ z%dO^i0>@oa+U+94~Wwy~QM3f)Jcx?Y+fC<^~E zSAb7ug$b6>aH90gZa7g3CpOJniF$ZCKh=nimKJxTqqXR0`NY=Lwy<;V&3g2${F#O{ zTsplg4cDaMGQTx=Yi{S2x9bwlPdB6y*chovBbz77*_{`0U3!P9qa&roHDlHAl&{yL zZ?H>ZW9vtEV`H`0*w)Eyy&gNCpXt$+v)dE(*sJ-OzXe`=`VYiJE5M0EUK|j@tSs0; zby?9b7!&HemtgTM{87CKACB4%JnyyT3-l>=7;0?7zvp)!$8o=*;Xj2aH?;ob#`ve> Ke<224JO2VnMu{c> literal 0 HcmV?d00001 diff --git a/core/__pycache__/views.cpython-312.pyc b/core/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0db59f10dc14bec0e42194af2b0a0df9e56cfb83 GIT binary patch literal 719 zcmZuuJ#W)M7{2pYT9PWkNG?(&gs7^@5p}jQ6tRK?YKLxFqF^7bgY8T2&TWGdDMNn% zWy!+C1PVW(|A8e{hN2UhfT3Gan3#Ca#6dzll3zdXy`RtBrm*_`YN z>c8}1+yW*r9lqH+Fhe93fp)&c;sl|#%KitVx!=da%0vIHUCyI_{{jA}jpp0*wI1$i zf&NzO>!O(F^gvioAE^xid&o6+uGGDOs?uTFN<=8S&1NKAO%|zA+4O0e2w9Hkag!^x z%}|h-zbgBbk$MO>a^f9`IC3p!Kp$D4&)dWoT$))SQwpW^B8&uKOpSF7SzzQaC0sBi zfvNGb;L}8q6TwxJyMSMIz18W|vnfX*Ip$ucE6r>ky9qg}FMkGRfWFzQ!_BkJOMCso zUZ2<-gQs7d>M%ZwFP++jQ#;qjPHp0B4|cCDbbIY{wf4i*%hurW&m~l{UvG@7_uubN zid$o2YX<$$j$4qGpxsLLsmBi}6Miaqwz@3wRz$cL(||<$kKRg{9Fas&*3FOAX4#4# r5VIApfRRfNp(>5YBen{zdLw=d%(ad&o}#rWx-&)hX2vppkQMy~jjp0C literal 0 HcmV?d00001 diff --git a/core/admin.py b/core/admin.py new file mode 100644 index 0000000..f046564 --- /dev/null +++ b/core/admin.py @@ -0,0 +1,6 @@ +from django.contrib import admin +from .models import CompanyInfo + +@admin.register(CompanyInfo) +class CompanyInfoAdmin(admin.ModelAdmin): + list_display = ('name', 'phone', 'email', 'updated_at') diff --git a/core/apps.py b/core/apps.py new file mode 100644 index 0000000..5ef1d60 --- /dev/null +++ b/core/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class CoreConfig(AppConfig): + name = "core" diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py new file mode 100644 index 0000000..dc3696c --- /dev/null +++ b/core/migrations/0001_initial.py @@ -0,0 +1,65 @@ +# Generated by Django 6.0.2 on 2026-02-16 09:30 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="CompanyInfo", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=255, verbose_name="会社名")), + ( + "address", + models.CharField( + blank=True, max_length=255, null=True, verbose_name="住所" + ), + ), + ( + "phone", + models.CharField( + blank=True, max_length=20, null=True, verbose_name="電話番号" + ), + ), + ( + "email", + models.EmailField( + blank=True, + max_length=254, + null=True, + verbose_name="代表メールアドレス", + ), + ), + ( + "website", + models.URLField(blank=True, null=True, verbose_name="ウェブサイト"), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="作成日時"), + ), + ( + "updated_at", + models.DateTimeField(auto_now=True, verbose_name="更新日時"), + ), + ], + options={ + "verbose_name": "会社情報", + "verbose_name_plural": "会社情報", + }, + ), + ] diff --git a/core/migrations/__init__.py b/core/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/migrations/__pycache__/0001_initial.cpython-312.pyc b/core/migrations/__pycache__/0001_initial.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed166608ccec6f8647efb494ef766ee2a9ca32f8 GIT binary patch literal 1699 zcmaJ>Pi)&{6#s0;iIXN-n>wXoT}HQ**3xK;&`wO1*haUZ{SmB4C>mI9zptq~$2NAt z2wX}sr0#%LkXV83z+gZ}bLb=xL)*}fmAEugrCL5!a+|HUpcWx<0KU&o)(*lP>E%7W z-~0dG_iH2)0{E*qpU6HA0EY;TkF7JCLztNb5I{-+St?Cs=`>9N8XNRewL-X__WXt~|Dac{Z z;c{e$-{=$2yD+--F?5@Y=9^?e!5BujKZfRAbVpM(1>@z8M$2)1Pr2C6rr6GMVn=;X zKLNSB+_jC&aBvU)C9l!ty^Tm2Djg|2BXrxrQ;oTf*eyr2tS+gA6Y98T(=r^k=@Ul< zpBZK_hl^sBIFeZwa*LrF~~(MP11ol7h2~;>2wKxQrBN+5t^>Z}YSewK>rpfhgJ`QN*X3R}kjI zqWE@RQpi}a6p&RphX-eeA<~fwkvb+L(;%mh*T9|hDRSfnxjZ|3SkAnJcVL(Vvx7$_ zB*SAvFOz8Sp6+ytB0ANVshAnE$Rm}a1X?RRBhaB%Q> zv7T7JUNFcyxP&m~A^fmh1gp{5)Unm}_|(ao9|ZSKhgP^`g-cp(Ni4?`7T-HFyu$ZZ z_+G0=uu^^2KEiAT*?32d<=SGk7>IQ)C4|p9RuV!bAuOD||Ne5~>{9E8bEN*o(FQS!++X)pK}94m^k_ zEq?#Z@a&n7&&;J3MwX7BTjt-au?&t90`YE(?;|eyDtzApTud(WZ#37X?!UFnk9fLQ zsRMkpc8&tw16J?B-&iId-4dx6f}t97Fy{Z@72~-^J5S^53c^WA&1n5_)E&AzXRqN0 y2+YOyW6tIdc`Gzz3}O+_0GM5v)EJ7Q{_q1z*z&(f`Da2at*J_D>UV$z*ZLp%Y0#4Z literal 0 HcmV?d00001 diff --git a/core/migrations/__pycache__/__init__.cpython-312.pyc b/core/migrations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b16bbb7d4a82ceff72e271008532b43f5da1f41c GIT binary patch literal 129 zcmX@j%ge<81gjrU$^_AmK?FMZ%mNgd&QQsq$>_I|p@<2{`wUX^OF=)epg=!4zbI8d zH#5B`u_QA;uUJ1mJ~J<~BtBlRpz;=nO>TZlX-=wL5i3vwBM=vZ7$2D#85xV1fh+*S Cs2pto literal 0 HcmV?d00001 diff --git a/core/models.py b/core/models.py new file mode 100644 index 0000000..92c9f81 --- /dev/null +++ b/core/models.py @@ -0,0 +1,17 @@ +from django.db import models + +class CompanyInfo(models.Model): + name = models.CharField(max_length=255, verbose_name="会社名") + address = models.CharField(max_length=255, null=True, blank=True, verbose_name="住所") + phone = models.CharField(max_length=20, null=True, blank=True, verbose_name="電話番号") + email = models.EmailField(null=True, blank=True, verbose_name="代表メールアドレス") + website = models.URLField(null=True, blank=True, verbose_name="ウェブサイト") + created_at = models.DateTimeField(auto_now_add=True, verbose_name="作成日時") + updated_at = models.DateTimeField(auto_now=True, verbose_name="更新日時") + + class Meta: + verbose_name = "会社情報" + verbose_name_plural = "会社情報" + + def __str__(self): + return self.name diff --git a/core/templates/core/index.html b/core/templates/core/index.html new file mode 100644 index 0000000..ba22ea2 --- /dev/null +++ b/core/templates/core/index.html @@ -0,0 +1,94 @@ + + + + + + ERP System + + + + + + +
+
+
+

業務システムへようこそ

+

本システムは、人事、販売、在庫管理を一元的に行うためのプラットフォームです。

+ 管理画面へログイン +
+
+ +
+
+
+

現在の受注件数

+

{{ order_count }} 件

+ 受注一覧を見る +
+
+
+
+

在庫アラート

+

在庫が10個未満の商品があります。

+
    + {% for stock in low_stock_items %} +
  • {{ stock.product.name }}: {{ stock.quantity }}個
  • + {% empty %} +
  • 現在、在庫不足の商品はありません。
  • + {% endfor %} +
+ 在庫状況を確認 +
+
+
+ +
+
+
+ +
+
+

人事管理 (HR)

+

従業員情報の管理、部署・役職の設定を行います。

+ 従業員一覧 » +
+
+
+
+ +
+
+

販売管理 (Sales)

+

顧客情報の管理、見積・受注・請求業務を行います。

+ 受注一覧 » +
+
+
+
+ +
+
+

在庫管理 (Inventory)

+

商品在庫の管理、入出庫履歴の確認を行います。

+ 在庫一覧 » +
+
+
+ +
+ © 2026 ERP Demo Corp +
+
+ + diff --git a/core/tests.py b/core/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/core/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/core/views.py b/core/views.py new file mode 100644 index 0000000..4a02752 --- /dev/null +++ b/core/views.py @@ -0,0 +1,14 @@ +from django.shortcuts import render +from sales.models import Order +from inventory.models import Stock + +def index(request): + # 簡易ダッシュボード用のデータ取得 + order_count = Order.objects.count() + low_stock_items = Stock.objects.filter(quantity__lt=10) + + context = { + 'order_count': order_count, + 'low_stock_items': low_stock_items, + } + return render(request, 'core/index.html', context) diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..5bf09194d7d5c0225155b0ed6308ac8ad9698540 GIT binary patch literal 229376 zcmeI53v?UTdFL?zNDu@tLyDqcS&|8oqA8dHiT6W_Y|#=eGnS}#Y-O8+4uK&Fi+C6S zB{SVeL0Yj>yLI-sb`r^f0wC)=E!>^3KDwr!g2Zqx2oretkS>}+<| z-qWV%?7eqpFb@EdEJw9X{m1kb=HBmq^S{4)?>xSl0S+JBo2yE`nPNFFR(%mmmxbdj zJAFQj#c~VzKS};qm%ZeJU0osna=Op0KHg#(J@M%_Qfd|6rZ!uJe~>@4s(^eD009sH z0T2KI5C8!X009sH0T2LzUm*c+oH*;<=ppI4&igFF_k>4;tkBQ@CI0|_v*#Z@-}0RF zMBV4yUvz)W-R=5Q*D2QlS6}DPJ6|KlSU>;-KmY_l00ck)1VG?D5{RyAv-Ay(=L#pJ zLbX_43&TE7f#C z%uDIKcz1eUD$G{rj6f7mp=2x-+1W)r?NL32(hH@mSe4SHa`EoPbV(}bbF!|c9)gi* zFtke`9`>mof{K>ea&e(_DKg@zNGcfG!xJY*6(_-zzCrWirL`xX48@blTRg z<1XTCQgs$jm!-QFa%CxOSq|vXe1Ji-P}oB+@`vS>D$Es%@=2L zg>+$I-Zc2-zK%zOk$7~cllV~kIvCaasIw`Ss?8e`4#yI~T^+=O+SkE|-h-4EbMqG& za`8|wnT+4+AWqc58&n6cHr6g>)WlNJSR!<5dz)ow51DKlMoN+J%@b9wxFqu)wppEUNR2MDwYjW4dNP~mXF)Lv@qz;b@R){9Up+q>r z5p;AvWk7e~iZQashU1{yY2|{EztO z-sA2a)jiXdekso zsTMQGt$dGd(5bT|TiCG1w%u$;qY8Nv7O-}A*@hL*BvO`L$W*Os1e;&U$}AACd8up_ zc-tU1S58a$(tL4IlB|M9&L|ZtBv4r_*t*@s5wXZhC9zzkzHL1&Tfj-oUYjk#W$zRVvqd%Z#9|{| zJyu(wLn&ZE2O6{Jaq8E zO=Uv2-Mc})#8)o*`5wEsPtK_a7(9aA>(%AC*Vw(AH`t<`Tw2mYc0ZG3oi-x3Dd$h!Oi~-|8@Qm zzRXYYqx>4r&pm(Q`I_gH=ZI&}{kHor++TIy5I;@WW?)Zk|Gmd%3KF1b^ zt^M!XUuys7?Y9sCSU>;-KmY{ZcLKqkZ5A%Hqw7RYIw?og)#KfB9EIIj=i*woZnFEM!8mIj>NE=)RObfwMKW4T4US0 z=o6a_8zPxz`@WA5`~DF@YmL^5$DScg7~D<_hQe)kG%=s@pz4C9re0_r0jEuPyF?uTnqGA`9?G!zFJ4KRg z=Zg`$A-{`C(i>4#vPFNCT8!{am2xIj7q#;6r&b=S4Mm8Fe~ec|>5LRjidk4TQ#9$! zR7%WSUx=6u`gtlzXTvx#1AmbENqCr|`k9!f>A}yQ{ex%De(rb9ef?{JF=86n?opH( zj8$!V^HJGcQD`t%HR{ZV1H^nd=AlXrwoI$eux~3d>>qJ!icM+vGO7KXdNYm$nQOtFf^TMUK%< z(WF>jFIy^_jFyTp*>YfrSo-}PRG86>s*`PoHWQoSkdvuX&yVZcR$hDP>{HLLJoF|1 zATb+>ITd+&Lls!vbU-#$^yy7iY^v#CKQSE|Bj>;5QE%lIULBrlG~lBOM>?58^^9Iq z`06*`sJ(oBAKm6yry@^prOK1-u9NK)ZF)OZ8?*CmqQd;0RG8j~a$8{*BO8fDAmL!D zbk_`ZVXwdP=(#6fJG*>p<%t)^HW1^`c84O*WUeSQRJc~Ipy)JJP^9WB_}7yPBQXaR zY_g`B^`-;Y5YwSRJ5#P))YMfg>(_gUjX%_`2-aCCVpTixjtI3=bn5IBjY^J>ycNO? zj5=7 zn`)tmqN~@ES1!0sLv|`gEv72y=j+I86kNaG%C^ofDeIeOYXjuX2-4eDW&3ptMSyHW zUVWf8ih{b0B7v=MB(FA*R$8fsx&alzR<@AW7Pyg!jj7NscI#5KtgQ}WIhL>~db9#+ ztBBGvx03e{sI{U@E1=ejJT3Ej@{R!+jW()L%cZ7NsFt&tyg=X_4l%LnRd-z~$?&lk z6Sk0d1e_x=MX26Rk*QgdcLRu}B2sUuNUU29ke33SLt|8+-i*qt+tB;}J3IfgMR-g2 zufiXZ7{DGOO78i036Be>guHOO!0~VKKjDACzs&y|{uE!}e~sV6hxtCu7_Oz%Kd`-G54q4ce}IheeSrs-z~WQ z-nHWTGgpzs4JKVlm(SJK`9FyOEFb^^AOHd&00JNY0w8cX1g^1jA+Aa2a_6;nF2*&D zP~IdLDQDD%nBt9IJ2%EP#u|5Y*|~mB7gPMm8ap?{8DfarjX^ zbH;#Rve(XyaOMDDLe5p3sgb-m+k_#w7h_q5XkK)!o%3_1=v_q4R2(XCxNx_f8|3tn zxezlmh2nzi>|B6r2)d2Q*^0}0z-*K?(ilVwFn+pt*;Xdo5FZsBNx=w)*~Zpm|AnZq??TnEi}@_1n7ey zMO&)d08Ts_#~VdGL4-yrw<$-FiMG+c6)qKZW%$Sr>|ueET6lj$=DC_32q zYYav>;-KmY_l00ck)1V8`;KmY_l00iC}f!aFGW2xO_ae6&tPUpC%G<`ff6HZs= z#BeOWITR*eQWy+wPE=1G_~h-S*hd#X{_#7G?!Gm?dvSXI_~w(xLNm!D`TfTaPp0;K za?f3Jdv;YuMv4bNc5v=v$+2W<;pXFah2k?u4wX;tU=R1RWT$kuNS<<%MoE;%_}zr$ z8&qSd(MXJbA1b~7&k65X$R8FE009sH0T2KI5C8!X009sH0T2Lz)kUDg=9Rw(fZqRa z_-4V?)mF3y1V8`;KmY_l00ck)1V8`;KmY`;dIGrqzv_no0Du4pfB*=900@8p2!H?x zfB*p@$dxe_t8^VH66mmjF z_=GSl^a~q=Ug0JoB}9aPaJz6&xJ{VgzsLUv{#*RN69mC2*!X|s-{Jok|5JX2|6BgA z_&?`=z`wx%KK~W|asIRXzvk~J0DCF`DvGmPS|_W@(6~o*+xdSUSqm08QOnSvtbf z8(8Y6X~!0p4zu)nmJZR>xtXPdEFEBJKTSJ*EbU|Ibu8UPQ^!V@ZeZ!PEL~62_G?(` zW$8MW_R_R%ElYb?x`w6QG_`lJRA4F3QV&h7ZkD=O+R0KUO>G@4b+ELZrEPYble5#r zMiZ;e=5*rz|LUJ!XdwuI00@8p2!H?xfB*=900@8p2;lqwFa|&X1V8`;KmY_l00ck) z1V8`;Kw$L~!1e#??_;zO1V8`;KmY_l00ck)1V8`;KmY`A{f{vK0w4eaAOHd&00JNY z0w4eaAOHfZp8&4^SAQR)g&+U|AOHd&00JNY0w4eaAOHd&fa`yZ0T2KI5C8!X009sH z0T2KI5C8!XSp5V%j{j@v;x<}@&HSG^f7Jemo|Eq1YG2!SyZvF;JI0CCQiB4yvq%>_d+_3A=#Q2d3-{jQpi937)=Hixq27LRc8qEiMTLw&99`G;!%MA{1 zAi&)_Ru!k`CG#fC>(?oYj*Q>DccS?wa@hf2jzFHcHKtWZ?L~{hcDV%#RDCXY;x z@7;S$$(-0twz5!>$_zpSJpC5Lh3Z_InqIPBrODM?o-{2hRweqWPR3vRsMp~wj&rrU z*jTOmXB$bEq;fu2sSw5$-Df&xLo?IUv6*nDb%kqZe5KM(DYGs{@P7z z9Nyz(;#EwInJpI=N)@?HL_Axitw=>9v0x^cNiP&~cWIlF&3lvv9G#jxc(gtX%~lt2 zYHo$>nrc@&obH^iH zPJBa^X81?C9Nte5@%t_$UiL)bPlv+6%=ApEx$f>u(%s0!G* zbHAF`-HIM%*JmzP=Ht8D^{GRkvDSN=^Yunvf@5Z@sK3Zw%I~_~azKBed#|5sCwn`* zHRm|DG^ULh28AX1A+Mk^4b)Inj8DfSVblCI*S_W=GudokpVOKGw$IaVO*hb3b+ZrC z6gPMx^So!R!+VhIsbZ#vv+k(q_E3pfEES7J&Esudlj*@Ev~pn9E89_(>=WC6E=_ef zyr~p-PePj#a;YZ2!jv@RI-5+72BXWGBz1Ye+QCeAyIP}Y>o38*R^bvS44EM78Yf9D zxz6FukYnyKQ|Ftko~o;9*1{78Mh&m zbk6(mIjO>0l-s z3CE^`+8(5#YL}w9$$3D7tu}Eluo+#W8XVB3$(dwGHjGjK(j9JxcYK_?XS+5-S%;Z> zt@TLpG?}SQT_|I`ab8^LY@T_#wAn;Wm2F()z|+8?QB%VKQ{#VW+wdQ-wtGiLxMK`# z<*xZ$RZ3T+yB4HEMl!A133pKo?fh}a4UTslH#)fXJKHwe%lyx5 zUm!;RLMZaDTXvHFu)NO%mVZ6&@D2`g_c~ZiYOb7?@}>FWq9o})4jJQ6x{}L^K+WXJ zm1^1;YKj?eh}&Zv3OLP z7UO1vjmp4j^~8!29ZswDSAQzRoVQ_Ppd!eXv4Q#7yl z8#SAYFKfyfCtKJQ^%b+(GI`oXKbvS+Se_`Yr%=-=C|5cuO_Q;#LnS|{BNt}M5}9|| zv{-EtNhb4Pp+x6pi*kQ$ZOGw0?B{AJHh`7EQX%^3qd(H!C3Rw_#aJdDj>jWL6JOIY zd7=7-QK=ZxUeIl8z`s4%?%nTiHOq_=(jnuzs}>(~c>R8EX;^<}K-rYhw$nH|jD=K{ z+LGhaqSm2N-R@QY^cA74+7sqtW>N8`Za8f%`koL1f4S5VNSJ00}d8CpfL1ls5 zIg)QpnGXgu*Eq34`ooxZ6l!ubGguN8P3MyK%o!C@6=!A|k4P6fSdm$jzLV_do8Gb^ z8*O$VHVE@awzhls^k1-l<-3z|2eZ$8weAszx4)mO<+UDWC9EsiC!t9nvx3X&!CD`!jWOyc;h)YrVezj)DE3%d28EcPL+R}^e2CrsKTdIFDkUeox zJKXQ^E{4tg*39!?t&+NMnu+nNjw&G@p$hZ*yQZx<`ORDC67s~5j5U2n6tyD^<37{{vN zNbIlO+D9I~jBvHz&>!0LLek_GY$MeM#68+JyH3BK~8q2zPyT!YqBF;;dQn{F2$W+&ONKPNiA-_B$ zmB|kw<#{*B^J;nBF0#Ift!Eay?>5)RDXl4 z$6>eh4$>cp(*2xNPrKc+X@l~sJ{9HP4Q+PI5V0&&Nh_+0C8?tO?6wm(z4T`|=r7u= zv5~cYx~Bc=hQ~_syflyfNJ}?I#f#Z|u0Vb`hj=V6((8Xq*9W2lAp!(I00ck)1V8`; zKmY_l00ck)1VG>l5y12RR|qWJf&d7B00@8p2!H?xfB*=900@A<2Z#W!|35&T0VyB= z0w4eaAOHd&00JNY0w4eaAaI2U(C7a-;SLM=!vX>z00JNY0w4eaAOHd&00JNY0wC}% z3Dkx-rzJ5y6d4~MKl{Y9E3Z8G`YVr~d-Ao3LkG?*-+N~H%V!^d@%7VRJ-__w%5N{f z{;jW^``xdtJa9S`ApZp;flxRS4aDM!WUeq%+$ohyfvl7-j%JFZcb4X=)ly~K*x1RF zCr6DX;b1r(2!;cpxG$L67Kv{QhDMXINFow$Rgy~5>wlZ@R~F%a3unncSU>;-KmY_l z00ck)1V8`;KmY_l00cfv1YG3n0M~OQ;;{12m#%Y>?*UxTz47cz=O2D~t&4mM;Ck-- z@-t+mQ@;NHu0{B%@Lz=QewZ2vtsnpbAOHd&00JNY0w4eaAOHd&a8(iLv9*yOH?W+0 z`N5U@KTj^}$9M0Woa(lc%pS}6NA5rO`O_qG_r%9~IA*u<$iF}P)bk|k@c7<|!}R@s zo3LULR)n{NcdjaKXe^f&BEDeVzt>UPWk@-+w}VX?SEPw*cu3c00@8p2!H?xfB*=900@8p2!Ozq zCD3N$I4imScjEg0%7TV>5C8!X009sH0T2KI5C8!X009tq9|_Rwe;d30m%sn7Xc1l( zitnQ!Y#IbW00ck)1V8`;KmY_l00ck)1XdG)TdWStaBpBJwDOtzRzCB<>#sa|?#b6~ z-W3dnbA_4W&gsDXd}cIL9KEv?j0X~A2_(s~^5oO!Klkj)>Bp20-&oqiQ9rSvk+V-c zyYk9|vY&C{CzL4`s$!zk2o?FRVOpT7Lfj zEsOB~gtt}`XtV_cKmY_l00ck)1V8`;KmY_l00gdL0v)zqjz$}-4qLC2h6_B7=PYY1 zZ(2H^=O;9Q0t)yfYNJr4|)Y$`=(IN)D)?{s)aMz~Y^tKu{nJH~!8tp=5?9~r-S??lrfkjoDE za)qiiE0ujy`;Yjhj_%#-J8)=n-}s?pzS|~_`NoeP**`f&{Op^UIUSHF@yp1RI*I zrbAY$WXicxHCHSQ_^Q&~WIhm7{?v`_-hIQZjzEUyrj^~I(!$ZsA6q);!FT&d+P(Yz z7j~ict?ENvA6c?*cX<7NZh4muwpuE0UR}GP8E&=kvIhTq=Pl*M+`PWaqNK|RSK1YG z#e%NC*xZmy#B8=KRmi;2x}nywO@C0(4cc_6Sjo{|qX&hMI30^el5t(RU!kHL!gVE0 zYsv=&ofQSA+XOj2@hOM*AURaV*r8Hqn$Aikv0TlQlM*T>I6V_f#xfzD#g^7$n%8YA z$6!hXbtVa$VfENeHm5Tnf)qK4s1%e$X~s}K+#u+Jb?b68E5=9N$bdhVX!lMIwi@g@ z6lpz|>n#@Ug%9(I>Q$z_7Q5Bq&1~mt$JiV&op^TEo!yMPAD3c6TB8ym$jp<6RR$k z%=<*;gn;ZZwNpIxEb`r)4r=Ex)m+|i9#bgNvzz+PmK`S5E2Dw>i9_oX6XPNMBIk$x zrR@{!r23vfvpz6Uja`uWWwCCgsGf_HhR+u>qI?RVo@IoB^h82FFfEiQ#B5rmr+eg+ z8KgGe8?ni!An*AcSbqM$Vi8^yDp%P~2h9Zm5C8!X009sH0T2KI5C8!X0D&t>;8tt9 zCDCjBXJ?k4J+u7qnWe9sS^DOg<=UC0r_U^X`2e{&zYskC@XKdEzjXeQhgMEMeWv!6 zGqvA4v$S;Xk(bUaJ#eP>?3vmNd|tkfW-fpBz%D%hehJ)dFAQ%pW;_W~AA$t*3%F56GzhM#nkMPEaw~0^=0w4eaAOHd& z00JNY0w4eaAOHd&KnZk`mkv0qlWSWDT06;W1Dwt2w2~JE==1-a@JkE%!vX>z00JNY z0w4eaAOHd&00JNY0wAyo3D`&s0N4Mkuw&6A5C8!X009sH0T2KI5C8!X009ut5m2xH zt-?Fx{y#~ufB*=900@8p2!H?xfB*=900@8p2&^UocAJy4YS;g7)9e4YS5pJg77zdd z5C8!X009sH0T2KI5C8!X0D(3e$649+zx@4w-?Run5xxm7AOHd&00JNY0w4eaAOHd& z00JNY0v|8}1N001EaTi-?OXkQ!PK@$d|NOynhM7fskpVDe$k(0+}YXGCKQVY6ZHLm zE4lTL`~M%X{)HS6009sH0T2KI5C8!X009sH0T6i41kCsUzhDvmMEJscb_)j}00JNY z0w4eaAOHd&00JNY0w4ea@0LKw>acWk<3n7o(BdY4GM-AT-1qp|$G*7o*fT4qpR)!z zxr#GaXmQU!nTV(KRdE0R-F6G?K>!3m00ck)1V8`;KmY_l00cnb!$Ls2|Ns91u9Buv literal 0 HcmV?d00001 diff --git a/erp_system/__init__.py b/erp_system/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/erp_system/__pycache__/__init__.cpython-312.pyc b/erp_system/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..370b58556f38d90eb1e3549ed97bd80967d6d822 GIT binary patch literal 124 zcmX@j%ge<81XYhGWrFC(AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxdC9R)WP@tb$R1jZW xSzMBus~;bqnU`4-AFo$Xd5gm)H$SB`C)KWq6{waGh>JmtkIamWj77{q761pl8f^do literal 0 HcmV?d00001 diff --git a/erp_system/__pycache__/settings.cpython-312.pyc b/erp_system/__pycache__/settings.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7be1db05b40c70d006a4ef5f0c882d4251de91ee GIT binary patch literal 2437 zcmb7Gy>HuA5GVC5>cg@lCyrATG?K=V(@=GjI&l%Cr6tA@B1@_$$1R5vwBD0Un;$Ys z*%2po?oxDVhfL{IM2HK(BAT+$B*(qF@pHrU7UPEgUQ=JVe%7!2!TK(@+qY16MQ7$Bd`zqUyyyP?dS3vmP*6hN+ydQQqDiaiT7Ng;va zLJ}oV5{J-)4f{Z;XFiz}CeS3B0;@@M!5h=wI4zUSfRI8Lg-LWtm;!$n;Fm@-!gS|y zW>(6=mZn6>nlTsN~PF=zYq))uB4ZAGCK*|ccAG2D}+A#j9c zgWi*rHa7o{F9SD59R1}UX@+zH70KGNR|Z*-H51p{2EKKpVMv+I{_X2abz^sVzwzyj z&AXpnTexHIJl$VFi+A-od+Fw~D()>`y=RNpc9%b@Whgt{r(x>4W*PD(<0aL;FfMI_ z$17t(7lJj*>a?(FUm8=I*fb%{XB8?aq$VI{#}O7BOx-;W(+Sk!xE$Y>;RH>|6+~ri z4}9rHClj`B4Unpgkb?Im12bL@WUIsQZZcr9cB-@Qj5`{H#*E zwx#+GGz#nPz`M{UmVI+zds>-ps?M=@Q)u5FGd@kvIe-&gCg6lu z*xX~Tly?I8LX~$SY^5T4vv9dmE0jyTePtvQ`({&Sq*edbaODOz zb!87bp%z>Un&m`RSe|oF)S-ATSLJHrW9}O#nCDj3SDge~ES5L8y!fch*LWvcDDgEA zfdI;Ycc`^OK40WE*ed75tL1V{T(1^$<i_46k4LlmR8rhK| zy^<4hXEgyLuK{z;_5LgI)_n)OyOM<}%nmE_^d-TxI!@%is-w1o9~c?1b^ke-?_lWp zNs>JFQDorn8G^ig93tYWA0ppBcpaNNh|Rr0Ku#r@M)x_)Ir?6r1Qqjv(kzFHR&ceMcGdu>F4lfmtkD literal 0 HcmV?d00001 diff --git a/erp_system/__pycache__/tests.cpython-312.pyc b/erp_system/__pycache__/tests.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d807f27b1cca934d9bc1139922e1d3364e598c08 GIT binary patch literal 3464 zcmb_eO>7)R7OtM@o~aqn#BFAR#|v?6#YCR?F9}%@b^{?Y7K)ZQR&dy*7pc`umy>q7 zr)R6%z*x@0AqO8oB3uk7uC{C`If6jKdt#-P(2OS0M5Ul00TRBU7%rUlz3%B5C+ign zN=g0d)vKykudCko-uq8BnZYLe8Q75IPg0XC;oi44*$!HlTt7QY3V()RfwQh;T$V=%tzIH}>%s`}X|(Ktb;+i(k=UWDeV(6rXkAH@nyDo+pNMvL zdXNSV){!9RcSqxSHR3w`dW)UUbz~72&26ODTc^Q2v`_FKkJdf#J#?9wd+xOT_x>Lq zT36QGV|H(-kt2g;dmL<+9;0A(vc}iR2lhY+PV`3w;K? z*tdKeCb?0*B;;9xyCU(L;TWc|sQNH^fxT^jKeO?Y>l70rJ!f&x*8_zq+lW|&IfiA6 zw7J9KD=mi?sf!k8x@q`qkxtqcpkd&YkS7lxKC+lVEa7MdM%ItuX~j6l_uzRTLaA`8 z#ERX#3r9)!jd@n`J&`DJ2HJ!S$N3zuQpDjjjt|7M!LaPU1=F}F&YTLDQAkTITyyk7 zk*tK^20+Rlv*$d#k%3Ndu#czM*j4&{9fvI?ulmZKs|S$nLAX^9lGAP*;C6M zYUCzilHNCYt9RdOq4w-wZuLH~QoUMTJ$CK*+VL;m{&MNFrO*G_JbA8u@?7KO>`w~G zk8G28K8-4VPLsaDW?{Hq7;Y9O>V=8x+U8uXFwrQSf$8k+-u{($uD;Xk9jo__T|d5g zur@PW>m6(Ko?n*V&uoMJBE(PelZXWm79j=PR-zEOlnN zgpVG`^~kKn{W~GF%K`+ycNGW#itcUFeRaC8Nr&omXm$45>uaz7J74>oR-;2V=-+Rv zdsnhovrTodt`4paT^n5+t*L_z^_gYm7R@wip-u}Q?fs3zi zX2aud(Ea!C@3~1w_+hYWca(hnNKpbF(ayGTWUFmR(c52^{B}NiU|&UCv@=hnlR%Nx z@zu*Q@YQzS?5w%RS9kGc*!5Uvb;Ox+WG`Ur(b=o)us8ll?QPd85&>)_r@^yF;AaGd zED{uTTj<J>@yY)|){a>$EIoWkfK>#W zp}IP>YF=~JoK5qqi~qVPr*=6On+81J~sSelG;njst%`ffG?ArNPYwB=A{p+&w z?e0)%_Knp0MpkEU(4*h~rjGvuw@AlLdNcssG*li`52_Ab7ik?LiMe1i;4`|8VF~LI zUFQ?%4ll`6n1jSwauw56bTp@3=C`8vE{YisQ)k(H>j3 zGSRY>zktd=VT6T9oe%?CtBQpQ+ey?D5)xRtiwfb-z4e=`uYNE05Y;y||Nf%9ZLCK8K> z&dMlHG;7^fgWmGtBZOd_!;}=1i4ejbqXd$16cK>ZsFDh8M-BEDwa(0MAc{)dgK_hTL@kVWqg zMyq*}jZm8Rr3t#9lBR~-__L~wfs%?GkE+Fs9_-athLv5_IDBPzL$a=2(x&_~+s%yj z18HE>$yEuB>w2E^Lmf)bDD4=LG?#&;99IeLPYFsp%@N*KUzF{y+qy7#?sdwkD3T{9 zipsf~tkfu2y2;cHDLWGin58mSA`c`}*OE=?Jx>KLEhVw+OpN^lIF+BluS#5 literal 0 HcmV?d00001 diff --git a/erp_system/__pycache__/wsgi.cpython-312.pyc b/erp_system/__pycache__/wsgi.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..22f500c115b12edb5d502344d893cd19942a8a71 GIT binary patch literal 618 zcmYjPF>ezw6t?d|Q#mw3K+9?&mPl|83j;z(NKK<4NQV?5Ww~6>FNq_ceLA}-saQHO zv9RzPP=5+b5lBd$KotWUC>s;Lq*3|?zwf>0_rC90{=BtCkhixNAH;i%&_x-nta1tF zhaP-H9Q6^$Jdn7Ly$@xOh5ZmCz?02Y%i2$BYrI0d!mphL%LtTk?~#>R;w zuY2tdO|=?|5gqD+LXpR2W-MehFZ2Xb8xhj66yD_8fT4B_blHiJ=M2G(VE? zK*AIxohF4?lvI)dr-MO~=TfAJ6rrtiam;&Y^;y1W*l;RY6Tfp_L=Pk;5=KlGfF(kbXk*Qq;dY%qQ8JXrVaDXKwS!@*STRb$`!)4`iDD z_!DA`{{~fDncqa1{6Y_Zpx_-jCEwBZ7qor86P-6(-_YLA`rWVfd#APHx^Maq0KBvJ literal 0 HcmV?d00001 diff --git a/erp_system/asgi.py b/erp_system/asgi.py new file mode 100644 index 0000000..70445e0 --- /dev/null +++ b/erp_system/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for erp_system 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/6.0/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "erp_system.settings") + +application = get_asgi_application() diff --git a/erp_system/settings.py b/erp_system/settings.py new file mode 100644 index 0000000..96d956e --- /dev/null +++ b/erp_system/settings.py @@ -0,0 +1,121 @@ +""" +Django settings for erp_system project. + +Generated by 'django-admin startproject' using Django 6.0.2. + +For more information on this file, see +https://docs.djangoproject.com/en/6.0/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/6.0/ref/settings/ +""" + +from pathlib import Path + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = "django-insecure-(fra)yw3&6crq9wf^(b75$*4zkxw*d17o!z6+9m_v9#8z_$q9%" + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "core", + "hr", + "sales", + "inventory", +] + +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 = "erp_system.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 = "erp_system.wsgi.application" + + +# Database +# https://docs.djangoproject.com/en/6.0/ref/settings/#databases + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", + } +} + + +# Password validation +# https://docs.djangoproject.com/en/6.0/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/6.0/topics/i18n/ + +LANGUAGE_CODE = "ja" + +TIME_ZONE = "Asia/Tokyo" + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/6.0/howto/static-files/ + +STATIC_URL = "static/" diff --git a/erp_system/tests.py b/erp_system/tests.py new file mode 100644 index 0000000..1dadebd --- /dev/null +++ b/erp_system/tests.py @@ -0,0 +1,40 @@ +from django.test import TestCase +from sales.models import Customer, Product, Order, OrderItem +from inventory.models import Stock, StockMovement +from hr.models import Employee, Department, Position +from django.utils import timezone + +class ERPTestCase(TestCase): + def setUp(self): + # 部署・役職・従業員 + self.dept = Department.objects.create(name="Sales", code="SALES") + self.pos = Position.objects.create(title="Manager", rank=1) + self.emp = Employee.objects.create( + first_name="Taro", last_name="Yamada", email="taro@example.com", + department=self.dept, position=self.pos, hire_date=timezone.now().date() + ) + # 顧客・商品 + self.customer = Customer.objects.create(name="Client A", code="C001") + self.product = Product.objects.create(name="Item A", code="P001", price=1000) + + def test_stock_movement(self): + # 在庫移動のテスト + StockMovement.objects.create(product=self.product, movement_type='in', quantity=10) + stock = Stock.objects.get(product=self.product) + self.assertEqual(stock.quantity, 10) + + StockMovement.objects.create(product=self.product, movement_type='out', quantity=3) + stock.refresh_from_db() + self.assertEqual(stock.quantity, 7) + + def test_order_total(self): + # 受注金額の計算テスト + order = Order.objects.create(customer=self.customer, employee=self.emp) + item1 = OrderItem.objects.create(order=order, product=self.product, quantity=2) # 2000 + + order.refresh_from_db() + self.assertEqual(order.total_amount, 2000) + + item2 = OrderItem.objects.create(order=order, product=self.product, quantity=1) # +1000 + order.refresh_from_db() + self.assertEqual(order.total_amount, 3000) diff --git a/erp_system/urls.py b/erp_system/urls.py new file mode 100644 index 0000000..e559b27 --- /dev/null +++ b/erp_system/urls.py @@ -0,0 +1,25 @@ +""" +URL configuration for erp_system project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/6.0/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 core import views + +urlpatterns = [ + path("", views.index, name="index"), + path("admin/", admin.site.urls), +] diff --git a/erp_system/verification/dashboard.png b/erp_system/verification/dashboard.png new file mode 100644 index 0000000000000000000000000000000000000000..d9f64e15a03b91545ab9822e2cf2ffe7c5d4ddd7 GIT binary patch literal 75295 zcmeFY^;cW#^9D){N-0pF6f1?|#fuhi(cdEVI}8fprJPpF^Z;NTD{ew5Y1!FhBi-v9IX z{@veuI;DF!IL~ktWk2Y6rS0Dk8fXKTq^_32<~h^Pn9?T{zc_bQ3f4&cc7Ohtdqr^5 z%JZK3rj`631%mJ=c8`!B!WiUY7+SSH6!EcZl@>AVtTv@D_8hz9h|N!3y? z8YAlS>EFfkl2+n}Yg#HOjj*x?+Pw>!p4NEHG}4b>&P?bh)iMH>Eer}Dy8 zG*eEHjYTsCalGkQ`?AV|Zp>M`QLZi&bk^?RA@hthX8ApiM)e(NRH)4Q1qw#F+FetRr+SHF=-&=<6!ht+0 zARvwW!|>;ibM-gIr7k>YMQwDstye#;Fe9x}h$8X5pkBH)!{Yo)1>f6ycNuV(10qBB z>R6d+7)=vXnq)>VGTI|gaW5YZ_L8SWaWBUak9fAl|0QioiiZqOr35zzX#|?746i|b z66ROCx^Eo=#99_rTF+m15PV#!-{}2-lAQFgWiC?lJn<*%bwGP+chATyiOLuMX&I&ke$xm?NFIVxMGoq_+-D zVLw5;E8v$>(HN=dBf9f&lAl5YA2%PYo*mrMu$%NqN!!^!_rAP*Lfk-5yK&^taI$AM z*#m=QDM*gd#Gx^M2%2DY%ERX|*A*qbA&X>@&Cc0So50%O^MxEcNH$pu1T zJ~&g+9W3PuwJO;Szy(2p8Y$#*hZ)QuTC2f&aN(@JFBE%$cbG>t*#ine4Nj)be7taL z?NqkD`5u6$T@&kb`9RoI)v6>=x$1UBZ6>bbGKY(}&-8)!jo@hy@kZV!yJ1eZ>>r3S zX7?@aIcM$8RP0ZXb|&%(J}9sCI!)}|rMU`YMZ@XnqSXOn0S^ctP4km*q-*BFRv(W) z<+I1NE!`v{O85kLe*bvh{K0X30A?rzM|@jwU^LRGYkE0? zcX`5rKFNA(FZl-EuKP9sx<-c~U6mUldv&W^p`oh?Ze9CcPE_1Nd^(Mo>|fSEwf$AY zn7oUR_DtpgC?{}kuknbnwNy#D0(SdR)_Yk2c+Uac7nm%}%3Nzf(dz`{Z;Yee9#2C` zn`^@Ik9;tLga2q`c-CjiAGnE;hWxWfR$Nn4&TL8}V!L+nuH#*zk zwllO-AL&l;XdCDWL3}-%aUKEOD{9nzefcquoMUTum((Y^G6PO-iObfHedV3nPB{jA z1<`La2i=nj>7r{MEZS~_oCMP>F|}QX3}QIYL^~A!_%n!p9OoKkpSGX!%ytV;)1!^K zw%bIdq?SyVA=4lJ2VA~G(yyHVy>0bc30FRyu8l?6Jt*A$d@z?Ox%o7ZjLMc8KkVno zbr6G(ldAf>KwQoJ!`>-r+zhi$t9kvF%R+em4`1=9$xNQ}VS20OXnfQUb-==ba3E8*bn19wH!aoR4`r4bp;v~=EL~<8yC*iC@pS`_)EOFh z09n%3E(#+=!t}S83dJG1#u=}edCc!OQGLKi3&7tetlyy$d($L!fla)ANblgkhL&?B zlMq!<9)A|?Kfd^_wBY`=faGYV|GX92lKWg#8Dcn!AE&7RpB%OTo1jlvrAH}?*2e_0 z8okE#Ken9|U>@MxvosMjG->KAi4IgGV^*lqnDuHu`Y52^>1JyLf1vcTBR?RKslQc6 zy5pl5j<}bXMX>1UBH#K|ni(ElCJu8gZ z3VqnBVZ23W;GO-aY7c`qU3RFyVaeB>i9N=vS}pacJ0@NTYSZx0o=^0X6oIQhuBRc#p?E-ZgH-NghD*i zP;1_q3}O8ijh#a7;4pe2!RT=1YrZVl%MW(y_kOL+w8(no=aQEprIP5+VV+wYvsip> z_X0%S>D8nDD`LBnn+Ie)zZ0YL@nj^IkKZd%jzKaPXg&7@G6$w{V*#Y6qepP(GTNlh z`$a2&7)?sM{Bz6IE>?iq79Bce>Nkd!`>cvL(D)N%_=YYzDRF6dy-Ca@4>ni@QXHCr z$OM+%qMzMa zxnD7fl`Nwav=2YEO4E?3I3n|`Ne(Zz7xi-|dn>skomn#phF7O$H4NK4@B!^|W?x zBr8E79daR3mi@@;bbyBqYrBLE!d&Ru?KPPk7_Oq9i0~^>egm)ZfmY>q5H;5!vD5#J`$0O!^t^Ccz+Q{Q0EeL%N(aDWqSwp6@=G#)2|iYAK~I3Q8KCY<3Z zTtoR)t5TJJk)Yk~s<6qml{x1*>!4{d$Snc79(i5s?9#!gg`_y_9Mo}$AH1Gv6gH`g z>aDvhe5pu&8OtGceBu{i{^(pKmR7E%lg`+c(vU6&gX@ME+vDFBBt7LTLU(rPEPX4R zziKYuimG-=mW4#DY==X~66JAIS1eFN;+y=2j z5Sq8!GezHLXiPW$M(v9!{9Qh4?LPZnXl?;9q9(u0WU~J(!4Bg__X~7KL98`dP~3leEgTYeoP1!+tbYF@PhS^0pk)w(u2McuUFcvKKku7g zwy}2py_RErz_$Iz4=so;;K7F`#1k4(2Uko7S-BDq=QMO25$0Z;NaZrw3zADlG~JTH zZy%vGRRd+C1(!u<%0L3I{HAU^ziCW?Zv;sXWtcHq_OQ64A(N$_ou}#ZPKe{9r}K>h zBVBl%SpnvgW?Po9gR|Aa&V4;+LJA$e0g*iZkH@L;Q0T9XS4*#n9`FKWC8)Z3KOSD# z>ny67OKevh#-S@T!RAs2c&ClTo3x6pH%nK2WpwHJZEkO=-I}(oyk)UYT-|3P(-_^; z@n2CN-zA+Q+ZkA))gXZd2m*&QuNm!D|E;7Jy4gnaJoTRV0ktQjT> z!{~gmt@A$?n15XJ9{ii;>&(&=~|(s)Z)MD1D0VUF<9r-Y;%C<}2PNt_JQeRO$B{)+9XRehug z>t<04F&5FZkYZ2dv|XMPbJppmR0-Bi6w_iVEf?tQ0~Y;CaDt>yPI?Lt=T_-yxSPOx z%YG>c`FoA#`U!l2-p0AZw)d94ZIB1$&e7#vVeJq7_j0f6xmhh5b4IfHU;Kk>=XV7~ zege~6SYyRO`KHWwWc*Pp^D;6`FwWteWJ_gQssH+@-?a6D{6lLqZz#k@(h1@TBe=-w zOdy(;yg9);yqNK1^a8d>e+NbnR0RH9Ygac>2XP$L7YXwB?~op@2yet?^nzgo>lK10 zkILuUTryka9l@rQdt!}N!L%oSaYL^+Is*bPSY1)hozZTe9d%xmveZ+#vBWUcn%JZt z+W?0dCg>iUwgRY6g8bIhDDc;_X?-}p7h`J|-<&-tit{H5`@^H%GN{_CsZ#3yWgS!yy(y6&v+|z( zsD6^;c14nHMUuw$XUEV?AM0E0)wVTu9#9ZqA~*v{`! zH)IYg1hScjyKZ?nsXZ6WTqP3HX0Ghy)G&VoQ(#=!zt#^~2HQ0TVfHIb*1@odF!(%! z8;T_PNUnRJVS-DV|1Q;IEmM;-d0M2EnoaJych43Nrs~?b<2@976gOc$rQG$*zKk(A z?}iooPNYkWE_woKqQY4#kd%gP1g-s@eH@1GebP(OXrDQZG%CP1=L>fM0W}SkVh!jy z1!}ic?Xb%YZDgd^?B16Wpk9^h{&!8rqv$C_`ss8<5kE(O^hp;W8sqcY7dkiOSm@4s z;ft*(DisbS>Iaj@H;+SooE7#m1OtFBpd&XcaPk-26M#x{f8S+Tyn&}FcB|H^%eN6_5Q_yslA-?G_;C0Qb3-v#e4HU zsPlbQ8S7HpATw0$#P`^Pze(7Hw&7~96jlT?%UwEV&^5FC<^fNU$67<_rTo-AXWVo( zbv)@Qv=waht5`G&*^laY9-rABZ`e^thGw$ua#fr}nXB@Wk4SY6N{9Wt*MwYu27;P% z;Se>ZHvt~2!h=qxOv`1}9l;3>>FR67Jx1#5Q9QC*uiNhUkSD#505^&qrP7IB24W9E|mw%z^1z(%rk+bTFUcyab_XrmPr*#R`&ug&({1c`)g*u zpRO0HCxHv4kJ+aiRc3~#%Duc@!%2Oa8IyT+8xPxb$WJ)ApXHS=M}`;at)gZ2-@(g&?boAK*EXuPnf^h z;X&DUzx&sX{{t`dLfKE-t*e^e|5dwQ&%u8CSut8r1=D`bSDtV3F~b4S`{{zDsHLZy zj3ImjoS;0k-3pGFZ+t(yn!z7-mFGfosLT(C1S85esU3rmOE+l<-Z0TKT0o0lyaB z-afBUr~Uv)k@FtxgCRFcD&Paog?9}dtaib;7HpNkZm340iaPv27;Q_nT0LDa6(Ms) zP6TaMJ~+o;IsI7K2_A7!WR!s}aCFICS~*lRHyr-oq~BRAy*!Dpxq%f)BHY|Jzk zMVx}RoZIpyrr!BlHePi)s@FjLmK=M#rit<>-ctbOS##QxOy;LMw|WyTtKZj|<1g{r z%wN1g=6Nn`28sHtQ80lG`t%p^6gY23==(!-rb{4akC!~r74>*#vIZh(yz%o#s7=UW z-lNHR;i5%Q17R8EW5R#jr>%XJPiXC!Iad)fRZ%KCtTfUn`&WZSCm{@TPf_1;S}uCw=@lm4D>!CQbo@wGs? z$dJbkED2Ur8fNMYGT)Z7+i_cy`aO}G*U2|hS1<$)+&35sR^Nr)lIn4Z8X%0{)TS3< z*6TYz%duWw)2UQ_Hm!OL+9q)7vT91%O*8DoJ>Fz|eRVZjAoP&HB8lcUF06u;82BXh z3Ej?3UZ=+QdpwiIA9Rq;Z}ylh{kje%FDbP4WY_EIjtI)?S|RQD_5j;pNdt?UhkTX9am^l_f1ov|(g|HV1S_{%G+@I2%wJ`8c939Nry*unDXG$`KUq?+liI<~^+g85&7tI<-etNo_ zYh|pM@w)WrDs=b_V2O1Ccp}%_3O!3uBz*H)olGJwP34Q>1qb$08ikh`C6M4_Ai**1 z$LpV3@tlb2{1aWYGxXW%Xxt3SX~z9zIl3vTmr|YaZKX~}>SR5r(W3k!L6|P4XS9ED zO2@+!KypgAU~1jY zOpgb1FZMK>C*7M1V;{R=PNPkK0#I3!C$CwR==5E~Nw z*QeolEoI$*`mfqJ*TCmG%CRw%8wiN7K4m@xYDpw^U&fybG~P~Tw5mK<}u)WA&EV${1{;S zG1uP@J$_5T)BN@PKUK2V))XM!omM=VmLTst2xgAPxck% zWi9W{(+XOS@BintXL+_fDl#~JScyYOV9@Bl&(a%lb5E|j$o`hiC10U1dyn(qD`M6- zzOR+ygf$Qd{QKBfHqGbEBL+;3(J$m-|HlQq{<9`N^53gJDW|PIPLKZY;{EeyU;j^% z6?jO^nEBro?lWBt=|}(D$M*l5!vz1oRyhBoV;=wOp6Li|f8P704n#Tkt)ME1pbe$d z^0wkgz5N0=AN6v$!2G6QRJ+ADH=(kvxb;xldvGN+?UMu0eX&d}=-j|;h7&!R`m)=kaNip`|Lmo$uCF_J44A zPi9Ao8GXZOkeA>)oNb@@D$=eUf6^1|YFw-ubz9cd;NH}Du2WMiwLL%Oy@M6yaU|?Y z?A@MyXf^G!?xI=Uz2)Q9=0e9zMO5Nk$YwhkVeOo#hpsSq@v{aFFooF0&0R3O3VWa{ zaPRB(6NF(am*_!$$a7ORKx`$e$h7u{e{97@_h0~V4!n=jK-^wk$R0i|DR~zwBYb`Fcf9>lP z9@^aUsf!{)^K-fe~ZFUQqqi=zV+=5Dzf@#PfH7Y{YN`NrG)`F`Wb$p_`>mn(R6KV zOyKz+-*}=?bL5mSvCb?ZNRLb1^x*Ajd4h?we80mVYRvW}wKF-OYOqb~D6gaN_B(%g z{Q%EY4rt!R26J>@+xP$;D?hP8{N7rO!1+jWhEo{ygdk}keK zm=oz&hAiDg#Sw~zv*F?3xRBmIo|J0}vU+8F-~>upy}GDTrj>sAGq?{f^GSeWyo&u` z?P%dLJ@tM%Ri;f<^cbI~#0Y2U*40?CZyk`mYg$gl;088kA`$OfH1%V#d;7blabhNU zn^)H85eP6wk1J*^wU_xUMBzsi_>`D;%!xzo#`ab#!GGP#`e69`MqX>1pR=!P&Sj)E zZ@QoYsUOV?P_dOjFwX4A{JQ>^PW2ay!)YF?lDDlGC7Q_BclHZ^D)X~IV6HQMp{4O} zcn>z_Ph#T!Fx*{v0ut1kXt~nLW6@A2WeW&fWHLcsJutqXmXg7GW*E~)WD5P%=w#wZ z{YODLJ9_Z3eZ=1$nu5^%U@5Y$?uVmczo~YSd3kSMjS$~jh?RgGRkq#zKAga#<7>ig zp!&~Ke5ooRza~BP(3jCXB4^tVzL5zH$BhXtRyi5xCk__1*%!|xCX)oCzR+Vlab(x1 zYL4Hu$n$wvj$}eQ&#LPvghXa1RX_toO!2hQeT$I$kQ?djL{6Wj-V163H|;z$w{-Dp zu_Pi)XyZjeuqbki(s*P8fmG$K2dJ6)!Rf!;7D>c7QIg(usJsGqSP-e#ZB1)qoUCI_ z_SR#ww?eMTR|NEcv!vxhQ&X+hlu&OiF0p#4|C3@9Zs|wDUu~*E2YaH9%_o`*R2YuJ z0SCiFoy#kq1qFaCRjFKz;p6|dYX;4l|J7sRhjdny#lW9ohg=9FhtcV9$+^{m2 zv;%P6F_rMvYwBYyMsq-LE z(7c{9{iytg$^{sd|6SEwn1MKLo=ntGqW-D=w0xdW3bPixL|RRm`3p}7ueP={>Kgh3 zjo`d}!OKE+TOV^9cB|+mm3vPtEUG)Cih!u3X-fPTCWV*u-o5sb_5(#0m?TpFhbPkT zOc7m`+em=!B`B`l`nIhs9>-@P(F@73ju3TB)kBy-%o>Py9E58z;}^JD&$em}355WC`SYa#H{;_H zU9`W=#Y%|Dmnx+^dBwylTmZArB@^$Uf!Frg*McX8M{1?rpSS#@`UMu&niG9R4_fXO zBzqVUx+Zr25!?v0g?}!*BFSkw9lO%8e=7o9R}+;pM31Q=OpQY@jTTX$eS@xqs5s!Oax?`R1!Lxk4CHBP*^-_wvu$1QlS_rq3N^Xy7z`gv;1TML) z7d5MKKLy`#=|730h+h^umyiwV&4-MUwMrNdp#-?DGgGaA{Syq@74JM#9Iy~Q|6z)> zRl8|30LnsBM&SPQ7bS!CzcAAAxR#sS^fz|{ukY|we|-Y~y6R~GJD#0r*i8&WY_|`5 z#V}SIj=Nl`zZyB{%GJtRw~zBJB~wFhtDB3D)LlbS?Uw8iR*&t%VEA}Bwy1!EqZ;O` zgqLCE^d{60OGlA!N5SlVwmRhs=VGw`+T|%UN%&4>9WLpeO#S8)y-#~7^lGj+=4@(Z zRsu+KTawRYZ}nA4I(MnaS8teXc=csgCUnUyVbOLg<;GA3Oj~(1@9%p+QKH=fqGzQ> zNZcLCS8LqMV5h7r7>>_*{bxE0V)`KUtuio5Tz$Cn%kJSEK%GIq==nv2(LvDrY8J+> z*p9QIS>N;^^Z5^hGUF48$Z&q4x-=E#e%qH-*f-DL-(QFdd=m)$yGLYYR!0ZtBwntz zn4<)G4{XUDaHFD{qf={9#W&Y7UBlr}!02_Qi~qLH0LK3 zelnkdDdd2*NjvxGckpZ6cb{n=+%#Bzj9Z=NvJf>cHx-|uhe`osd!PRq2pki8A@6KO z$&gwoGN6_0_~tq}>+x(#wJHr{)>@|;eUWuTPM}_q0=!jv?079%WvryMo9WHTY!i!H zako>5Q``mc{(>DeO`MryiqGx;E1uv=AJ!>avAnpU$Gn86E&>IIfP z`TZBD@b@0`r=69sUp*ri#t|L~o8*Gi`0xRgUQB_1qUx+dv}c$&5;#>G2D3{scB)Y1xstFL*UZflT6_W8_es0Ny7Eo_j|P$4el*2{Uf^k4os*Cs!8 zE4>4UdXOS@%2dgz7iEiY#Gqbt&u-FZM?zcRo&>hfHe(@*SPO2JKCp25yu}ZtCdr?5 z97x5zGEGXv;E3K+m9~NI;7}q?cfnaJFL&*pMx>yYqdx@tGNiZBVrO0J@TaMaCk(5Z z@Jpx(zWpk9sY%U}JLUKxb2>$>pr&K2Ql5l|$SRM$B#B@2ITl*TZ6INwy*NgE5DaUo z;FN5!$oetxUImzNa|!JKo@6sN{M|DVlH(%pzO7fCEJfW-dFWv`j}VxT6e?StD+yD3 zI6q}!7~0FnP|mM4Q@L ze!6^iB{`!tI%ON;=|~hV>;~GZL5QmrEiW~fePhGkrFb|gGMc-@pO3$q>!If63n5%}6dAPII*rZ(>3QM9u#rh3gL|_J zhQ?#OE_2K9*P4EimI{@!+8M+ZL)G21P9>Sx3uGFw6j94pWSLa{M@9n1dRKT-)*m*@ zSJ9t*F)u!ff2<+BD9Ksfzm-mdq!Hefa0*>gc$H#|RQ$Wq_OP@yu!2pmF4=Z-;p;Em z!TTBA^0K8{6NSs0BFhh=jObX<|HlP9CSO@AmXIX7^#1ge){zTYt2*p>P&U8xxl~pX zp_=EWjR|b4w~V2LRaxyyg+{i`%Ece;4~&?s+c$|+)8;9TCD-+GZ1+4T58Klw#=#-` z`t}xeM|iBPtw|e_xW32nYo#>4C^v;#x38rXZ$8=v@l+wSKZ~j{%h9$v`ie~LYH#jf zbLRFe#nj4(q`<-934H$+E_LfD%3*lGGAh9mZ-t|#;A}>veSqyMMHzX%Hd|E1(OB~qg7}8(zCH@GRyjQ(nAXV5tZn(#@7e4>4mIr=Q4L$jD0@ES znGuFH^+edT?y$1sR0kRB!baltCTob7@0(^vE>!YZ1;YAHX-k}&$88KL$pta_anlcWlx3gHo=>&&EtJA7@2ULxPu*-exsn>7<#uZ{rpk zhi3iw=KOlTC1h2yoq)Jbyo0r6GP1OIRh85IJeb@P?l$_UuPd&8*Wvkx(kF0!eP^-y z3z(d{puMfHZwLB8*zX$GiE?b^*aP(qVge_%I@Px8EE(2$$?EVin?HLhvIjhM>;KSX zT{1Wsb_O!3dSbiw$w#&|sGznViUqWO%kd{Ky`Bt;cU<19E?4cH7k1wYt5gtzewpa# z`jsR~UF)MBcsH(^Jgu#WA6Sq6It~_M&fOiqXkH*}C99<=tPt@kTx9hp&L*SvNxF!Y zZn8z}{w*WPsSu_{l$#Yzr5K#*{87rx8~b2U9$VGeNZRz_{^^gYBNgl6gsGVW)A}-5 z;oo)6aCd8Mo!+`@3w+5@rNf_PaRZKY6|(I5edJn2;kU-z`fTy+f| zPXd(ZLB2jY{RIY_!p7fL*@jeA=sW{}di)kzqL-$AI%cfr)_6G_Pta83id^t@He+3_41I1ZY^ zbJO~6(u*PA*yBe`j0mUl>?oSM4#=vdZe;44*Bz_?8KA5uEpNa0eNL`Z774VVYr^Jk zu#EnquYa2_lV5us3wiL1`E6?)On_=Q?|`P-?r9fbU;+G&yHw&pXSx`eb7@^q6f5wq zepmKyK)tWU7v!d#0s+Uoyh`i%oL$0zDl^dIpnkr|p*jQp_Q=M6x$;?z9&cH&krw-b zkWf)YL35T1D5Sh(;?GnOf5ex^ zJ~1^fd1=KboT>Vx5CYUU+oB#lL1YR|(<&VnjT+29i4z(OQ&*k+EuIgz(XVto0jxFo zO)yj*%u+kUbUfy+jj5jrdk?nrI%cwz4p(R9NQ!~CzlF1*%Wf2n%jYF|KNk<172D3G zg6J=bDmYaU6^Jf1o1M&qQW1TZx;1&_nO}4^@cCsPUI*8Pwo&oaQ9gvX$JxMn3U9O4>%b{mS#J;jbHeTRJul1 zJjkPrdGIXt$raw9NmWZe?B>1NmSC)_Ui-7Mo89e@3Y{8DO?-6Rt);gNE}}>PY6l74r6QWGzr=kp3gizcn1vP=>P--7 z37KSNuYxrgY8IEQtAp*F`i8HDQ2Rk4KiYeGWRgAYIhDnQtYpK=2#64dzK21kGezAe z*f;@%o(*N|N%P_hX5^BeD99h_rS!WuuY5NhA8#M;n8wMPGit5A9`p(HNGf_wyg87^)rBvi=*|5l%<_JrCst*A-$10X**+lUe zPRW!+vp;+*11LMbob{yYZhZARhteFm0v*lNMAhFJq9skS$xiwNv7EE9t)DYy2R?__ zl}?s>z_)!lSgep1b=B+~-0)66&fTwd8+;WFQaVME4r<(0>R(ap{4h@e;41{bcf#&B znTb{()XP(m5+I`~s=~s+%*O-0WU^@H$h2z{Z<81#Rz-r$Vw3}fQi4`p8oX3r@ zjWANo;4h6CZKO@%j>vE6y7IT(CnU#>`?%>QdB)e{%W~FY9AU)Lj)#B8yZyvV{E*TZ zjx30rNwNW6SQyG^D>~j@s=!BMAJ&J7?`Zc=vuYb!|vA3Px8rmb; zawvX5C*eo`*};N?HV;swZnP7kOZLny$r$eH8d#@(mt$q;I-L`2?9_XtORB}*FP-BD zm9fpftCkXx-%9BEmqmQg#3YQw_kj`e*_6H@*8H3=K$CokE$FWtJRqioras~6lF_Cg z;_Slt7(y+hY1kE5YfcqKadYvp1ifAyLZid^h3i$)x6Rg)3BFkAbj%k@XK;hSN%1h| zWikMHGU?T}Xi}Kb~!rUozxrx;oMm`%oapNJLdi6taf%^@ecPz5d?0ji zbGkqDNz|;m5``RKKGi$d&1KJYDpsbKA4Uil<2ehJG}+v#x3_47@K7=6Uxk-#mi>Ww zm@3VEg?k@zL~W|dURjALX_M}c^Tb>o%~GJ^gC?uO7awY+WHd`S>VXa%(jA}Z-qrLk zU*GVh3(5r(WtNO_Se!mV1%_vZ+B7Gmj!&pHFaJ{3nkfH(!5SRGrQS^WDe=A)#801{ z-rizDH>tTvW-;?6tJ2tberCNlI9U>T;;~ZO@<2HE)ga2sIl{%=&p!d~J(6H@!1E*J zi)avG%6OI<3$x?qw!Qo^KBAHL4&*l_)i=3;yCWtqYa-*vc_eL3!AVgZ(mZ#apu5Rq z70vV9+$hb3;97-~KO6%6lN^yZuD2RgvO8_%D?X|xLQ;rM0j@aIqFC9nsmDGKVZz*? zgdV{s*VqG6d(sjZm#5o;Z8Bs3)SfOFeE zO7)_a!TVGE^29Fw?-V=%{y24``_}W^bF_ysUcJOK_fn^X(-7B)uhFVbR$8g3 z{?DITFR_77!J_=X7bU~x$g`Q%mOfE(tV!vm0_JAV!93}?#)+?h-B{Ufh|&xS$Cmy0$% z`y1)JDWNUhjGP*r562jMnr=E@xn*t^y-7_p6vKaui`X;@n3lM}cvN|7HVt+Oc?g*B zz`b^iaylH5`EqK9S8u>VX>6cD)p@WU2f-2`ML4KiE;(|%G~h!{5%b}odipHMyL-Mr zdx9A8ZD;VvBUBRlOANPM)M|P+D85m(=sBOM7fDNsEG9g*Z_qR_ufMM|TP)Yr5~u=n zl*@BmUC5TGej6g0p1Hd~Z&_FEGn1cg^+4g}P(;62+V0*E!KiadaEXp2A`Y)S*>cQm zsj8vKZF?2s`YKMSRKEvCuehB5yDBca4gJ8Z0PFsUicGR%@QRN6);c9z-FA5QgfSJh z)EGS;Pu*Lc1N6nc419?9Xdd*P~)w>mz#h}^?_)$-|!^Fn+HZf=K}VuzZK`E}0F zF4q+5O1*mF&1_P6a~hr4bqDeEtfq0zUe1~S^k!_3Yi134j?{39nch8&5jqS zscU&yB#}k-mU?a$%w%pcc1*yySDvr1)2Nm{+vqYr@T0USr@QV6v#Ykc8jjF31tI~O zhvl%4PkX4!!FaK;r#dE5XPghWb)G-*E~qD(n;D*Mu(y&9@qa)}I_elGGM1xG%XbH% z11v=~}gE>$<|i(`A^zGk9v#2-scO;jXkJS1{v`#cG* z1f68#Y!h|u>|L;IBk7FeuMR}ho3`#sw10T)gx5IgBJ{cm z;X6I9tZZBCbouKR^;4!_49_E2$i6(Er%d$K-Ip;QkUs%aXST^EOUsXx|5{$CQ0N%; zSPE~$690_K!Q(s$B`z|vavJWJG)2R!_fI~shWIj!-=TCn*op)FrVQuyL$h%%B3p}+z{ zrH9|=g+5(NJNWApGFt2f03N}jUSg^cVl#7uEHkDm%X`K?oGLq))UU-t&p5|~O0Y^d z6KZ*Q604lf$;N+MrMv?+juy<`6~TC(2E9md-DMMn6*> z33~NV(S1FLJny&69s)Z6y)Uw`F}GUF@i)fNes}W;8I<>rbxulk-d}zWA8wnC98YiB zFLsx$73CLv|ABbM1*Z3qC*5`9BvK+(!n<`xSu>FnS@u1I&$2+{8h8&yT4^ zw)&E@LCE)J7Qb^r0G6w;3Zl9}QbG|`yi)dfHom${;_BA{sY(984W5iRk-|Ho+8TQU z>$iil1%@+NUGDz=R|SvCZLB^G%oVS=-=(HKE)RwEPO(UumixOw{x7DVJ45BxoBkvS z%3Lh6S{!7ehF<6z_I&y!Cd-mu^342@Ux;@2==QfFSm+>3&tmDHpose?C~!I3uO??l z=q%?)4hC8r>p3HP8`GF>Nj&vzH?sp4!(J}bY*`x1sopwr{ZO2*+&bZ=n`o`yY?N1E zp`0-E0MB60hKcm{u4Qyy0UmDFz9UEL%WJw}>tj*uVx;(qjP z*IP#DLBV1+5k)m(?R5CW+cvBR>COI630=Lcp_b0~2t?G|!OWc%r?u)ZH z0H@$IH_OteayjCM|BUj;+%;zGmfw8sJbcrdf1OMhoevXPmy0r>5DE3rVam|pp2Qqm zZ_icP-SkFa+>C*}Aow?XHJ3x9kJlSkkEp1FQnC1CkNobj!F(`K-_yGENOnK?EC$oJ z6~%3j8jx>@9FXFzb*3S73N~jUe&4gx9+ywWq@x88Aw<`W|Uj0o|ALW;%o9`iB z+)>(+5eJq~5EW*!)4kqhCI}Wi?4))|fEu}6`1p^Y&4;Zaz7%AqrFyy%^SBsd|B~JX zR_{XaY^IO)55vU>_EcvX^mmt0MSIV?Q=8*7_t(d1Z|k6SuD0QEJ1_&hKjlxOMjR)j zidlZMW-p`z_ZecunI!lPd{F$&rr5%LBldFV4DqgA8|M^UdP)8y0(8@e-oHt$T`4nqYFnhcjQ5)k1!d zj-vFuR4N~LryK>>2LOk>dSLC{$F(upPklV?FPjazkv2T}c^x{XV05u-b{I-k=% z#E9=aaL80JLe%p|uerlJQsiEA($HXzV%zt+&Ud4?%7Z~dg?_GL#eu+Pd^bz&}9JD`YO_)FU zTylM*UVbKSH>i$X9rF{Z>L9DgQ}jHT_$+p8G`Bwdl>nOQO=_P)QABTf(bQla+?7I?IlW zebsM~b&o90Vj5zm2dE&>HLak}l@3XGr+5CSoSh6~ zoOkC(SxY4hZimEWfWL6dmaHwvH|bsOYPgW^um6nVTOg)n=&WFbM6RT$q$qc?JUPuh z_A5^g=5lje5yg5CGjQ$&0oQzJ_$K)yEJr<4nX%BgineH!@{s(NZ^q?9pwEvs@M$;E(KdhZsC}Bm#RU!_Eg65qSZEoXry_e#HzrW%yPRxvQ(De=z z-8_-LzE_sU?aDUgN%MK60H^S%A>;B)R`{uu-F!+S&dk(yLpmJ0GSK>t1Wzem8mXK&-M~q;EaF%4P!6zcSzEj z$BfiYOK5P5V;*O8SCBY%`T|1iLC)Scc_0dDaDA1kH`RzvM)=GM-7 zg1eUna{)>2r96E9nGLCkgfEI<4E*TM4?DQ-bmi4&=l401Gn@U=!(GyM=I2u{9eGv3 zMS1Q3;!VOQ)DU3e#Rc??3)H(@nWnii5Gpq_uAF^HOh(2fcv$t9=$q3(tQMjXs{vW} z<@z$eQPu3<)5mWhkh!+AdvvVP*Z6wLTCt}dm4_#%U&ofeEBk~O46|Byh5gok-1rr6 z&u#ZQIm8khR4TsextIR%#UpG#69kd)gCCtwmp+4wCv&>i*ZmqGcW$fxQ^qQ<=bh*3 z)tgm5l%@OGT$i0-zOsZ4C-UF3G?RCOAr#Z*x@!4e+SE0jNH)XSG7M(R3F_djO zj^2fL?!X$LzzB$xL`KN1tE4fW6&Kg-!&vak%buIp++U+LukAk?5NrFJ≺JzEDkH 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 literal 0 HcmV?d00001 diff --git a/erp_system/verification/verify_dashboard.py b/erp_system/verification/verify_dashboard.py new file mode 100644 index 0000000..8d94109 --- /dev/null +++ b/erp_system/verification/verify_dashboard.py @@ -0,0 +1,25 @@ +from playwright.sync_api import sync_playwright + +def verify_dashboard(): + with sync_playwright() as p: + browser = p.chromium.launch(headless=True) + page = browser.new_page() + + print("Navigating to dashboard...") + page.goto("http://127.0.0.1:8000/") + + print("Verifying title...") + assert "ERP System" in page.title() + + print("Verifying content...") + assert page.get_by_role("heading", name="業務システムへようこそ").is_visible() + assert page.get_by_text("現在の受注件数").is_visible() + + print("Taking screenshot...") + page.screenshot(path="erp_system/verification/dashboard.png") + + browser.close() + print("Verification complete!") + +if __name__ == "__main__": + verify_dashboard() diff --git a/erp_system/wsgi.py b/erp_system/wsgi.py new file mode 100644 index 0000000..dc90040 --- /dev/null +++ b/erp_system/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for erp_system 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/6.0/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "erp_system.settings") + +application = get_wsgi_application() diff --git a/hello.py b/hello.py index a3eba49..8525600 100644 --- a/hello.py +++ b/hello.py @@ -2,20 +2,22 @@ import random import os + def rainbow_text(text): - colors = ['\033[91m', '\033[92m', '\033[93m', '\033[94m', '\033[95m', '\033[96m'] - reset = '\033[0m' - + colors = ["\033[91m", "\033[92m", "\033[93m", "\033[94m", "\033[95m", "\033[96m"] + reset = "\033[0m" + for char in text: color = random.choice(colors) - print(f"{color}{char}{reset}", end='', flush=True) + print(f"{color}{char}{reset}", end="", flush=True) time.sleep(0.1) print() + def matrix_effect(): chars = "01アイウエオカキクケコサシスセスミチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン" width = 50 - + for _ in range(10): line = "" for _ in range(width): @@ -23,32 +25,36 @@ def matrix_effect(): print(f"\033[92m{line}\033[0m") time.sleep(0.05) + def typewriter_effect(text, delay=0.05): for char in text: - print(char, end='', flush=True) + print(char, end="", flush=True) time.sleep(delay) print() + # 文字ごとに色が変化するタイプライター効果 def colored_typewriter_effect(text, delay=0.05): - colors = ['\033[91m', '\033[92m', '\033[93m', '\033[94m', '\033[95m', '\033[96m'] - reset = '\033[0m' + colors = ["\033[91m", "\033[92m", "\033[93m", "\033[94m", "\033[95m", "\033[96m"] + reset = "\033[0m" for char in text: color = random.choice(colors) - print(f"{color}{char}{reset}", end='', flush=True) + print(f"{color}{char}{reset}", end="", flush=True) time.sleep(delay) print() + # シンプルなスピナーアニメーション def spinner_effect(duration=2): - spinner = ['|', '/', '-', '\\'] + spinner = ["|", "/", "-", "\\"] end_time = time.time() + duration idx = 0 while time.time() < end_time: - print(spinner[idx % len(spinner)], end='\r', flush=True) + print(spinner[idx % len(spinner)], end="\r", flush=True) time.sleep(0.1) idx += 1 - print(' ', end='\r') + print(" ", end="\r") + def explosion_effect(): frames = [ @@ -56,15 +62,16 @@ def explosion_effect(): " ✨💥✨ ", " ⭐✨💥✨⭐ ", " 🌟⭐✨💥✨⭐🌟 ", - " 🎆🌟⭐✨💥✨⭐🌟🎆 " + " 🎆🌟⭐✨💥✨⭐🌟🎆 ", ] - + for frame in frames: - os.system('clear' if os.name == 'posix' else 'cls') + os.system("clear" if os.name == "posix" else "cls") print("\n" * 10) print(f"{' ' * 2}{frame}") time.sleep(0.3) + print("🎬 Claude エフェクトショー開始!") time.sleep(1) diff --git a/hello_0718.py b/hello_0718.py index f9ff292..a12f146 100644 --- a/hello_0718.py +++ b/hello_0718.py @@ -1,5 +1,6 @@ def hello_0718(): return "hello 0718" + if __name__ == "__main__": - print(hello_0718()) \ No newline at end of file + print(hello_0718()) diff --git a/hr/__init__.py b/hr/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hr/__pycache__/__init__.cpython-312.pyc b/hr/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87636b9276a14e20efb8a127d64f2d8defe140dd GIT binary patch literal 116 zcmX@j%ge<81pgjS$^_AmK?FMZ%mNgd&QQsq$>_I|p@<2{`wUX^OISa#pg=#PNIyP4 pGcU6wK3=b&@)n0pZhlH>PO4oID^Lw15Ep|OADI~$8H<>KEC4OG7kB^w literal 0 HcmV?d00001 diff --git a/hr/__pycache__/admin.cpython-312.pyc b/hr/__pycache__/admin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..754132601101861ad0e9d598a754a461571be197 GIT binary patch literal 1398 zcmb7E%}*0S6rb6TcDqoDPze=8)Jn1@Lc-aYkbs&f#PeP@YiFQ?`{nFn(pyPLyb?X| zHyHjDPlN+x5+hMB+%Waz$@jLcfIxzi>~H72`OW*@{ah~F1lHt_58|6f$afU_tI*qY zrYRvigb_vq5>l5^!ZfA_TBy5vXt+jbx+WzW;dFhlfBE#y^dX4;b;^XzLJdWqk8_mx!Fpqn(74i)~@LYcj(vv`nX<%KgT6qb{nV=cSp%!m~4j zkn{(^6~)rVjZ>j0al#ir8OJK+rKJ;j7xa~*)@cJ3OIo}1gv<9rNVYIDB#G`_KU;n zLVNkJve+*r5?7o7HN@8aXf2*?#8D>2YpH`?6<`i|kV+E-iT@f|M71UP8Vn+r%3el7 zUdZm4<=x98I3Ja=9(QN@iF^nq@H0w30-WfS(l2ECE1BOT^GCGOzWIJ?b86e(rxU+4 zjXv1s2V*mPV>2BBLPsas$?YZti&U81LC Nlyde@4Y&D-{Q<}0DO&&l literal 0 HcmV?d00001 diff --git a/hr/__pycache__/apps.cpython-312.pyc b/hr/__pycache__/apps.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..09616daf8b41c37ae246f47fff14c28b663ee0a7 GIT binary patch literal 353 zcmXv}J5Iwu5S>{&VB%O#!3AiL+$0x3NC+gTLhoi}u_g)fkF`>`L`p$TlQSTW!UfPu zRH@P-85#=2jMtgseKhlCciw|w2vmRDm*p+-md(Bfy=YHKY(Rm+404PSLBKUAu?FR& z_~zKTSTt@l*s+Pw99>k^Wm()W=XbVk5qr~)No*j67!|}qVeB*_a*TJQZOVv+o<*+l zq%4v=mC_8Q%uBV(SdXN9TqRlGahYGC<=wyGG^wiTLNnEqs?mH#2QG>FkYEiTe)x2y zNBhoSKa02N6Hv1nRaQFbY5QY{gir91mUb3Eg(>zA*6T%LbWo?ld* z43B}kGKu)*3}tANizYQDxjZo)H*`i5mY>J(ePFv%CGJipG&pIRrd&*941-ITj9B6g zt}trE(p0y6TBe@53ju6ntKe=LccBYWC;Y^$Lv=p!H)0%qm8N4~#T#u}-h`zOI;u~h2VG&^SFWjK}PBKl%o zu!^T)`aoPK+s_RwDBJzd7v)~o3p4Bxh>2Ph&?neOcvpHrER(Bb2L86T^JGnk06az9 z-yH06mBkzV{rmV!98P1M&nb7Gc?QP^P}Th)wJailPMq2#>?)4u+N3tPVaqObo? za~q+119u1hnJ%2aSeQ(GNyyI}XB@kPbe?tO#=a39(s#ciAS$vT9kjQA-k$bd3G_pY!E#)C}3glN}wKG75oTlvjP4qi&qM=4ULHEX$=$+$_}IW0SK;~ zPNeA+tuo;l&RcQrg>n^FQDA;Fe+&W+KyQr+|y7z*cz|g8mW~K z-kJBWBaEO$gO=72d(PUS9(-ur;wUG=&B`hKAIf$RY_#O2Z1l#$F*x`RN< zAg*e}wg>Ou9M2qp+4B5ttA?(Zul)roX?Z?hzII=AFfXiGBxm@Z${>JuZvFl7+TBO* zeDLtbJyo_qTDRys40Cpx`TdEQ?RQZ%`*$GuNJPAQf!N#-u&XuhYxSwjxdaK&wOzb7QO?&dZ`@3QmM8t zm3WT$tKgUIO64thS3(i30u>bN?H2j7^E^=<5iW#P2X`AWGi^NuxMwoXs{J;3r5<55 zuOK~5%mz?Y_l1^+-ySXm2UmhC$KQYH_DhAK9~S(_3-WP`$`LixKGD1gCfH9vaL?#$ zEN)m;mrE4;TuMzR6O`c@*=6*3OHr>s;jE0qF@oZ8kfB9#PKj_v@0P!9s8dtqv7~ zLn|+AhW;^df8eup;dQN$m@5T;10MY0g}E(%xabeBbZ=a^r`^>)J6^c>dSQl@{ATWz z<{i9I3cLXR1BY=>hl_#3t0S9lmI7yTr}1fU6rTo1@o8|v&afCCR6Fk0XJUz|2hjpxF288M9DmAQ0Tm>PiJ<(_DG0)UNZ+pL5e_bemiylB+a=K5 d?e+*g3v)NFE?&iP&u+J0IAM>!CeXEZ^k1-8-`oHI literal 0 HcmV?d00001 diff --git a/hr/admin.py b/hr/admin.py new file mode 100644 index 0000000..a9b6c77 --- /dev/null +++ b/hr/admin.py @@ -0,0 +1,19 @@ +from django.contrib import admin +from .models import Department, Position, Employee + +@admin.register(Department) +class DepartmentAdmin(admin.ModelAdmin): + list_display = ('name', 'code', 'parent') + search_fields = ('name', 'code') + +@admin.register(Position) +class PositionAdmin(admin.ModelAdmin): + list_display = ('title', 'rank') + ordering = ('rank',) + +@admin.register(Employee) +class EmployeeAdmin(admin.ModelAdmin): + list_display = ('__str__', 'department', 'position', 'email', 'phone', 'hire_date', 'is_active') + list_filter = ('department', 'position', 'is_active', 'hire_date') + search_fields = ('first_name', 'last_name', 'email', 'phone') + ordering = ('department', 'position', 'last_name', 'first_name') diff --git a/hr/apps.py b/hr/apps.py new file mode 100644 index 0000000..20721ae --- /dev/null +++ b/hr/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class HrConfig(AppConfig): + name = "hr" diff --git a/hr/migrations/0001_initial.py b/hr/migrations/0001_initial.py new file mode 100644 index 0000000..50cda8e --- /dev/null +++ b/hr/migrations/0001_initial.py @@ -0,0 +1,125 @@ +# Generated by Django 6.0.2 on 2026-02-16 09:32 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [] + + operations = [ + migrations.CreateModel( + name="Position", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=100, verbose_name="役職名")), + ("rank", models.IntegerField(default=0, verbose_name="ランク")), + ], + options={ + "verbose_name": "役職", + "verbose_name_plural": "役職", + "ordering": ["rank"], + }, + ), + migrations.CreateModel( + name="Department", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=100, verbose_name="部署名")), + ( + "code", + models.CharField( + max_length=20, unique=True, verbose_name="部署コード" + ), + ), + ( + "parent", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name="children", + to="hr.department", + verbose_name="親部署", + ), + ), + ], + options={ + "verbose_name": "部署", + "verbose_name_plural": "部署", + }, + ), + migrations.CreateModel( + name="Employee", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("first_name", models.CharField(max_length=50, verbose_name="名")), + ("last_name", models.CharField(max_length=50, verbose_name="姓")), + ( + "email", + models.EmailField( + max_length=254, unique=True, verbose_name="メールアドレス" + ), + ), + ( + "phone", + models.CharField( + blank=True, max_length=20, null=True, verbose_name="電話番号" + ), + ), + ("hire_date", models.DateField(verbose_name="入社日")), + ("is_active", models.BooleanField(default=True, verbose_name="在籍中")), + ( + "department", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="hr.department", + verbose_name="部署", + ), + ), + ( + "position", + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + to="hr.position", + verbose_name="役職", + ), + ), + ], + options={ + "verbose_name": "従業員", + "verbose_name_plural": "従業員", + }, + ), + ] diff --git a/hr/migrations/__init__.py b/hr/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hr/migrations/__pycache__/0001_initial.cpython-312.pyc b/hr/migrations/__pycache__/0001_initial.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a18504e42138b2cd9b65ae736812dfedfa3be465 GIT binary patch literal 3153 zcmcguOKcNI7~WmK9Va-B9dI6Y;@Bjc20KYhTM0xoRM1#yhji!E95YA%grLdY#B>7|FNGrJD4OG3$oU1@e6 z-~5kn{{Nr-qrBWq;ivKG_rg^xMdit0?a>uFE4{dLg#r|yMJh<+FC#KxO;8io2DLQB zPzNcXxkv#m)Ql?9)&!{E8IAf4>c(kSw?qcVSO%HHLP+8hLNpRb`fwCLF+QXM)z(oM ztbC>=+M%L3$N)O12~j~ULqXlBrFetd2Mo~QHNz%OO_QozV_;L8ZCkXt>NPgo zOKf&*imb+5Y)|c2vkm*_RIt?>_=kCemeHD5S4Jx~n5)}h&h_dXr~$R0E>%CHSJ#G_ zkQTV`>%PXk0cQYbvf zY*Wyl4J7YM`Df@g#y~*9c{jk(puIRIL5G5Td#76qT&d2PLJh&u_3m5N{~p*@tUqJ| zyYX8RTOm!bYW#in17te7R*MFZ@zZErAY}LJrMx=7QhO`nNIU|u;qhRxsxAK$s^Ao>dtO3AbJ}D*?V3H(@Dv8yoTdRt-axpO} z@gg!tC4lXUgjfyID(2{i1t@|zGDKr)(KUC&7%wHlFp`i+u~if=O-?U9`V||Av_rTi zFOh1O+=d%eS84NC(5bATIqwV8s3W0%?%2uzZTX6fp0&u`sZ{NeV(cMn*tL@JuXf#fDVUw>ma~!@~lOn`@3&)*J@*;@_JTeFo9OgJwELb;;02mn(U|b@M zp|S%?q#q@>vP7;*Wa$z@`*9BRk|08+10%eob}fC81PsB#$lM#1pb&~2#)+W^qkJS3 zMGP23M&)2hQW^Vu2DoDbWQ8j&Rk7vrl$4o z&|F!zW*}`nDOYY!JKLtJbI!Jmv+eHjC#SQ{<7w-OZ zYhNul5D8{1p{Wjgvsd-zg-(MV`KSpya)>VRWD9J%((b_2Sk4{DxC67Db3Ix2iL|v} zuB=PD{8Pg@mp|k3&wA!|XI+HNd3$ZK{Y^Wk6X~u~r5@H5bKvq!OS9U!eMJxpWvee1 zemLtol(zOMDm#eEj*P2g);o7P>pGRT2IuV!#VY@YGQ!uc)iOQd%Y^x=rX23AY;P&u z-bec}-=EV|W1HOEsS-X!@5YQL=@@O(U-(4YzZT}WmO9mR^MgUZ`ZtXWFD|Ay=cErY z44Gc8D><&DwVEd%6Df+QE&?>}RV&6msRs|quSUEPH_IBDrdRY7-S{WfvZ^1WY5gU0 P&g#ury?;?;q=@(zwBQjw literal 0 HcmV?d00001 diff --git a/hr/migrations/__pycache__/__init__.cpython-312.pyc b/hr/migrations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..37c74393b756873a36064e95ca38ce801be0b443 GIT binary patch literal 127 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 Hn1L(+gP0zk literal 0 HcmV?d00001 diff --git a/inventory/models.py b/inventory/models.py new file mode 100644 index 0000000..f1fdd13 --- /dev/null +++ b/inventory/models.py @@ -0,0 +1,53 @@ +from django.db import models +from sales.models import Product + +class Stock(models.Model): + product = models.OneToOneField(Product, on_delete=models.CASCADE, related_name='stock', verbose_name="商品") + quantity = models.IntegerField(default=0, verbose_name="在庫数") + location = models.CharField(max_length=100, blank=True, null=True, verbose_name="保管場所") + updated_at = models.DateTimeField(auto_now=True, verbose_name="更新日時") + + class Meta: + verbose_name = "在庫" + verbose_name_plural = "在庫" + + def __str__(self): + return f"{self.product.name}: {self.quantity}" + +class StockMovement(models.Model): + MOVEMENT_TYPE_CHOICES = ( + ('in', '入荷 (+)'), + ('out', '出荷 (-)'), + ('return', '返品受入 (+)'), + ('waste', '廃棄 (-)'), + ('adjust_in', '調整増 (+)'), + ('adjust_out', '調整減 (-)'), + ) + + product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name='movements', verbose_name="商品") + movement_type = models.CharField(max_length=20, choices=MOVEMENT_TYPE_CHOICES, verbose_name="移動タイプ") + quantity = models.PositiveIntegerField(verbose_name="数量") + date = models.DateTimeField(auto_now_add=True, verbose_name="日時") + note = models.TextField(blank=True, null=True, verbose_name="備考") + + class Meta: + verbose_name = "入出庫履歴" + verbose_name_plural = "入出庫履歴" + ordering = ['-date'] + + def __str__(self): + return f"{self.get_movement_type_display()} - {self.product.name} ({self.quantity})" + + def save(self, *args, **kwargs): + # 新規作成時のみ在庫を更新 + if self.pk is None: + stock, created = Stock.objects.get_or_create(product=self.product) + + if self.movement_type in ['in', 'return', 'adjust_in']: + stock.quantity += self.quantity + elif self.movement_type in ['out', 'waste', 'adjust_out']: + stock.quantity -= self.quantity + + stock.save() + + super().save(*args, **kwargs) diff --git a/inventory/tests.py b/inventory/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/inventory/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/inventory/views.py b/inventory/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/inventory/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..c7b2799 --- /dev/null +++ b/manage.py @@ -0,0 +1,23 @@ +#!/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", "erp_system.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() diff --git a/populate_data.py b/populate_data.py new file mode 100644 index 0000000..d39d6f9 --- /dev/null +++ b/populate_data.py @@ -0,0 +1,94 @@ +import os +import django +from django.utils import timezone +from decimal import Decimal + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'erp_system.settings') +django.setup() + +from core.models import CompanyInfo +from hr.models import Department, Position, Employee +from sales.models import Customer, Product, Order, OrderItem +from inventory.models import StockMovement + +def populate(): + print("Creating Company Info...") + CompanyInfo.objects.get_or_create( + name="株式会社ERPデモ", + address="東京都千代田区1-1-1", + phone="03-1234-5678", + email="info@erp-demo.co.jp", + website="https://www.erp-demo.co.jp" + ) + + print("Creating Departments...") + sales_dept, _ = Department.objects.get_or_create(name="営業部", code="SALES") + dev_dept, _ = Department.objects.get_or_create(name="開発部", code="DEV") + admin_dept, _ = Department.objects.get_or_create(name="総務部", code="ADMIN") + + print("Creating Positions...") + manager_pos, _ = Position.objects.get_or_create(title="部長", rank=10) + leader_pos, _ = Position.objects.get_or_create(title="課長", rank=20) + staff_pos, _ = Position.objects.get_or_create(title="社員", rank=30) + + print("Creating Employees...") + emp1, _ = Employee.objects.get_or_create( + email="yamada@erp-demo.co.jp", + defaults={ + "first_name": "太郎", "last_name": "山田", + "phone": "090-1111-2222", + "department": sales_dept, "position": manager_pos, + "hire_date": timezone.now().date() + } + ) + emp2, _ = Employee.objects.get_or_create( + email="suzuki@erp-demo.co.jp", + defaults={ + "first_name": "次郎", "last_name": "鈴木", + "phone": "090-3333-4444", + "department": dev_dept, "position": staff_pos, + "hire_date": timezone.now().date() + } + ) + + print("Creating Customers...") + cust1, _ = Customer.objects.get_or_create( + code="C001", + defaults={ + "name": "株式会社A", "email": "contact@a-corp.co.jp", + "phone": "03-5555-6666", "address": "東京都港区" + } + ) + cust2, _ = Customer.objects.get_or_create( + code="C002", + defaults={ + "name": "合同会社B", "email": "info@b-llc.co.jp", + "phone": "06-7777-8888", "address": "大阪府大阪市" + } + ) + + print("Creating Products...") + prod1, _ = Product.objects.get_or_create( + code="P001", + defaults={"name": "高性能PC", "price": Decimal("150000"), "description": "ハイスペックなデスクトップPC"} + ) + prod2, _ = Product.objects.get_or_create( + code="P002", + defaults={"name": "オフィスチェア", "price": Decimal("30000"), "description": "長時間座っても疲れない椅子"} + ) + + print("Creating Stock Movements (Initial Inventory)...") + # P001: 10個入荷 + StockMovement.objects.create(product=prod1, movement_type='in', quantity=10, note="初期在庫") + # P002: 20個入荷 + StockMovement.objects.create(product=prod2, movement_type='in', quantity=20, note="初期在庫") + + print("Creating Orders...") + order1 = Order.objects.create(customer=cust1, employee=emp1, status='ordered') + OrderItem.objects.create(order=order1, product=prod1, quantity=2) + OrderItem.objects.create(order=order1, product=prod2, quantity=5) + + print("Data population completed successfully!") + +if __name__ == '__main__': + populate() diff --git a/sales/__init__.py b/sales/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/sales/__pycache__/__init__.cpython-312.pyc b/sales/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a92cf11e681838e1a52aaaa69b9e7724de3a1f1c GIT binary patch literal 119 zcmX@j%ge<81Wr#TWrFC(AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxdC8nQPP@rF&n3Gzp sA0MBYmst`YuUAlci^C>2KczG$)vkyYsEiSai$RQ!%#4hTMa)1J06#Am{r~^~ literal 0 HcmV?d00001 diff --git a/sales/__pycache__/admin.cpython-312.pyc b/sales/__pycache__/admin.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d4db9a48fafd2a5bd7d67707dba2a77ffaf3f195 GIT binary patch literal 1869 zcmb7E&1>976ra(@uJ%KlIJ@iCZgFGm6jX}cLlaXdr6rgUT5k*KNf#kYV_QaAZDzC~ zTlTO9Ly|+m6pDN7p@$g%DZSLV;ALoOpuObgvWA47`ku7%M@qmQ&>PLno8NoyH@}&m zO|wj(t^f61aH0|NCl2yf82^k~l#pHG6Q718qBf<(S9~>8BGpzS&DJ8_)}w-5phO{e zh_7uEUuSf)mIIyj`)c-Y8wvrBYiBF@A5-@s8nzUx09ZxvY-DriZH~1+p0q2k#ndif z8h}~4Bxd!snED0GGGJCNiD~w#miZjBwy4xyKMLBa<#g-ab{Mo7hl3_9s~`=> zX}b|~99edp2*QQYa_a z4IPWzAly@U6T?h`Y3=E}f& zQd5I0jH`K8zd86~*qGm1$sEz=e^*l-pKex+dX_Mh!UK=-DL`%UX^j6$PBS=%2CF&E z>HP~i;qrx?6qvv^`T)$Mb3(~E_ElSFg>`BdACol-SJ<$P$K)ZkOZSMS%W^8AEL&X~ zUarz|jN){BH(}CXQ74RhjLB*eCvNDtQQU1OvLF&S=?Y8b??P}shh`p(rN~+ilnF6i z^K@9t8$LlQe53ckd{1{tlCO{_dY^m?zJ1zP`f6X>N5w&-qzCt^1?alycHrieh5LY^ zyjcjE*8~gKWRbJ`T_zH##;coBTZ?%l3*Ls?UT3o8I9})q;Wz@rU&l7!sU9$kZ<=RZ zESy2(fr+=kyd03<4D(6xz?lAF>Brko8&4nnYTP zJ{+tJugv^XduMRxg{JG~F#(ea8Mn2pnymSoz(c&?#qER#s~q{4g_J+R@o+fO!i#9q z*TMYSUG0W0AHOd61W1Fkb+~6p{|YjnN+-Kdsesc&FDhFaA43p$gFfLO0R)9l`~>D$ zrIh|ouKz)n4$0DqrqJ3BJDRi(Can_!1E5y9I%qzc*_zog4(Zg1qR<;V%SVm*gU0*_ zJZ_9sqD&v-^m*UnA$>FRy?IohJE+f{`cD1FS3jhaCrX8yJI$ks*@KDM5rF~XzVSCs HrwslJ#0r(- literal 0 HcmV?d00001 diff --git a/sales/__pycache__/apps.cpython-312.pyc b/sales/__pycache__/apps.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3f4688553a2bb730f7e168d8646c26bda4ba0502 GIT binary patch literal 362 zcmX@j%ge<81Wr#TWrhOj#~=<2utFK1)qsrY3@HpLj5!Rsj8Tk?3``8}3@J=43@Oa1 zjH{U;>Y|t`Su|N+f;gItw>TXO3Y_!v(lXPNA<__%5z6^20Ax&ONM(p(Oks#(N@0v* zu4K|=zQrA!n3Gxz(Rhos7{u|@WVyu=AD@?)n;IW~iz_}pH$SB`2gK%yk1s4u%z?_V zfasMBpFuYK64FmBD9{J%2eFFv3Mz|0{s9v#Kt?e;kZ57J!7bG2Qp5w3@dG&_B`Yy6 zJzo!`tq9~dh(>M@3#^bA$hyU0196635kHU%@>a13kodsN$jEq?LGcS4Bct#H&94kV H3akqNLv&CE literal 0 HcmV?d00001 diff --git a/sales/__pycache__/models.cpython-312.pyc b/sales/__pycache__/models.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e573e51abf680314d42495ea33afbf5b1ba43091 GIT binary patch literal 6063 zcmb_geQaCR6@Sm4&-SyO*l8)W`DjR6%xGFz>CjfSD^1Er)3lJ#3d8bn{azY}7u($T z+%{3FdPz&2K}b5(B?wKVY>b2iNX4XS+0bG18(GG{Jiv&?vy5nx*mf@W^3wmfQSbZBl+z5Hmha)TP);jwa^J&grJOe4 zw0{pL*Xi)_3#f{Z)hrzmQIZwtarGThInpUf!6l6u#*%%=d;^^!Mq>P|$oLHgMlu%L zqR5Jd3FEjye+xId3ZF?diz^cc}{LsnRd$SnBd1v+4XId zw`>)u&Sg>^)O;>5pF6KTFP5BT{Lao&pGV{N#S}HtA(4fDfwY(n$ik)9XWx2tcCdfU zpxHYDrvzCFA6MHn{)9x1MHER02RfvMdw{b!=Faoa^t?0E`^TByzA+;~DVik~4m}f- z2)bWv4Un1MOO#`Lrsq}Qo9UgH>3Mg|sF{z+f$-CsDIAk!%DsRai-EH;3opMnKX&b9F(BbD?LEKNRIW1ol}nWDaZN| z%Nf`AFTUn!Nw+)6m~d4jTBlqUDObfv^Q7t8eQ8%i{DH4c2J@CL86X*sHQ%bMhnlT$wtOD_ zJIpLO+o}Qm|4$~IXcO%dj)G+30d)!*O(pz%Ac^LO z*^AH4zW8&<4+OD*pbzVbK%dAb0zxAggLDD&CXKJz{^8F*xCB8@6N?x+9#R#}B}&0i zM?i+)2?Ql&DX!<=n3x-WfnfGrVeed2+$^~Htlmqpt*h5aFc%d%8wMNs5fJL!75MZ& z1tF%j5Klw5RI?X?UoI-C?!mCHvHk5<}{X}U4@?S<+C5BREimx2K=W5`3Tbe%#apb8U+&tx} zPI;ltol1KS#}5>ZBV2mLxuT0<%WQ`eUWy}3+7L^ocJ!r!CRt#-7`!4}8+B$s zLTmB2Z7^O8Mol6B`GjRW8`*wZE*lngtExQ*?+Jc{vbwQ{Jiq zMtBrml2LSvB@?B2-clN+9)NLgel3q!1~Bdw*8nZ+TVH)dWmfj)i17J3c@D z+}!0JecTicgtFY{URyYSK_9gR1L2@VUqCFG>3MUe_ct@W@67bPH`6;#(9R&!76}Vb znn|i&8Z^^I=bk$^`~Hjb@pFLk`+-jfc$A`N1FR@!sk(DRuYnLg5K|*UIC4@z9HBV| zvkkc$31%BwKFkg#=0_8t-@>JS5WE8??**b+MX5CqlU4dADaG+U_>!*nyEDDdVx`ja zCn!*|Wrt=BwnZSm6!H*q_diKVc6vNCA(6cx;3lc40j4oL$W2ladN=+u_W@b0 z9(WmQdZ-l8Bn9nd=GVq1IFQCJW7XCwuqhYJmV%m{dWj%{`xH-KPJJiYg6WfY<24jor|15Nd7&T`?(D*D?H$`-A z&mk?mk!$1GP92l$jb|mDX1ihU0D`m6-8~`>)(suJ zco4e(R4~=_tX;?Y%$iY&b!cX~tY!?zvc^-XLZBlO3#(8k22Mym1F3;GG&7xAp`N=y zo31rQmE4IM)dGn#pOko0-aVt@+wEiRZ->Xi>Dt{NdG~x&vL|7l-mo!YN^`ePbNqm< z&(`nAqTZSU)YDu|&3l_4YZCT7c<7;h^-X%!Y2P0qQs{X2fYeFrL(RHxZ_~cLb@ikX z7ACl7jcclJ78)OGXn;hRz5Z#oI24fD zQVBoh5|FdZ4TE*9CEj?$!<1}HoS1S~rQB5`>n4v}X}R2zeAJ(IKM{X$+Fi9`O1Las z-;q4}M6x}WcAtRx(v5>_r%E@bN;i(G*M5*LZHzxW?cF@MbIQ9p<=s44eeIFt;YX5B zh11?hykXi|o;Wh)EKfPhM?I4**Zs-XlWFIv`2HoF{Rh;mJ2MuexlFHQQ0E~0@(pnT zTc!fS<@_?Z1z0M22bRnt3p1E!3mUx}qurtT;ljSk`y7lHD@k>z&Akr=De&QSqo9da zdSA|_1wT*u@OTPZ9%!?H?{`UV5pKY_K=+qWFm(f%mgK>-G{Lm8V(D4V@1Z>p^t=h? z6zea8BdiaK&3G&B>;$v)#UETb5OiHQR8+{MX- z^8*lXc{Cy0Q7pwTyjl}XJKxDgG+kmYS}oldPn%tkHk%kd7eStf8*Eq­e~uIQ?u z*NwM>)a7OBqww72$?v*0m%#QSAC}N@<} zZc4Jg_;`EPeL-lx0ruqkYOc0r`i$L7KR`$~8)CW*zhz$lzyO)(9|f%)_f*hwPK;=! zAE=ce5NXzE_MY|=d@?Jss6>dL_9IyH5zJ;#%+%nJDL{@Zn&s(}^xq~3K{=o(0Oz=i zs;a6u{Z>F^h!NBu`arPgQJB)IERb z6VBOZ?c)cl9g%+(Yx3FzUVva27?X``BrZHDPHfjQwK zy26~s_Pn`4P_}*7bS4soIT8V)S+X@LHItc|i9Ca|1PSF+pr@e!fQ51SY0f#tm8ZD!kGV=}3tu4sQotiEAc$fP zL4VS9*@nHRkc5F~Wrrh5NDaa9gjMOdl>I0Z!g&gF)I~UO5%3DNlVEV`_d@g#f}7Bs zSuel}UJ!gNq1(mq{i*H^60#ye4^v(Q@(tVjBT;6lNEcv9Ec1iIErrmcUBHo#D-#K|Vd~R_!APUwX3f81bYbFiX z?oKv6kuH5Q{_tmJ=a&Z7ye(s7EUp{a``ThKZ^iF2TNgRAdDGV}qq*t^14IWq)UwfM z(`;gUAbdPhD;~>!uxcZ<`gb_JOfVnBuf+PNCTdYcNxH`Z+}F5W`ZvJcq#Ib!D#`&M zH;gRHe#&h4l&M%W@$9XM69e6S-HQx#7dJTIxphG9lNTB2F5Y$3`3yJFfh};m`;L;m5wuXCbVf<9+~M2nqkH}=cSnuHr7i=EzV0H+WzOPgjb2o zm`Ph{d~`1V_51#F@n6=h^K%%)_ss2ua7V zBk3G=@|?gO;E>}z4mq)7j9DuiuzqJ9*6*-uoEKdMIyfu}#GjNCnqV-+2?>7KDR9^|7O<;WedIuN%`;YCWsOHXav^utGwZZg zPYB4%q|5$nO2~)&*_v75p=4lH$#r12Hd|ND6|B}X*`Uo_sSA?p;jbb4ge`{Ps+M`w z2+~az(oZt!rmD7i)SPWui6h}gt?+I8wUFIVo(1jd$Zh;DBG>*H$Ze`XZZpfSxk`2& zD1^3T!{s~x<;WwE*jj;v3w6SGZAf%ICK4ix19s52Kfv8n*=@EO+Wv^_cA#z)&Gy*p z;%O#br8W~B+If{n&p>rNn|;ov@jTPm@a;G_4%dxs{_gBpZI!uDmAUYD=gbHM2#J(q5)!5pP2GE}D0b8y7U^Vam6SfYb&g^R|-V-kLI(#eGN;rob#|Onj#CNEC zI~<3*LKxLZpr@zj>6o074Ovo%w=bg`Y7%QikkJ4U4)%*q5|A>68jEXKGB6@FX-!T_ z+IZ|OJWhN%)<935z$9=IYa^)3aVhT*HmFAm8D}#Ha~eIKlR7_)CZzNqx+P&Gb#D)47OBUI4Q|W;a^mz5t{te zG?SjqPhJI`{8TnS`FjZ6HKItVw=4tBR7O!s>giE6g$wi+$t^;G)l`&;8w{Lr^SO^Xgv zi*Ow1P{5%S$2wg904|afvY}gH)gY|LHJSNks!N|{7q5J1Sz(Te>xhPcalcA`VhC8a z!n$yI@y5*J<&S|gs{~T&Ph%7u##+Eo4e%=^)lACJSa=jlhUdb?vr98)3uk^&m_9E$ zHM(nv2jLS^MlrMqj4Tsw-H?ooF1o>k7wZNj0=_BiOP`#(f1MVKhXsYvH*|J^MMP)y zQ8}H)$cppKAC}I4v3T<=EVxHxMJdfM&7NEQeA1eCrX{%~efndF%bNAYrBoa<1)5TR z^0WNZZ}L+&@{?cYr)ITom}8VcE#;@)rv*0oXREF}@lh36(Y5U$!^+Fb$Qv*1pNU#s zQn21#9s^ZAH5G&B7&b5w47DVWlW9dA$9SSDeSXztcPA`1*(bB2YqRUo%FHnCk z(uPK?^*}>>jK6~hP7?3i87XDR#(05;6$a(vrMbeH3s9vjR7Ra2wvrKJbwykZVB(TN zU7x72qGoeI9Q8&58dm7eXB&IPH}Ryc8lG5ZDV2tx#Oj%W`8E|DLePC`u;_>W zS^vDZJ?CvV*SEo1V~ZK=yf`o)?92r_&4_4*yUY;nEc;xIO+}Y?eM7NJAr>tL%H3{&lJE*LhqL}t*P-eb!Sfoi%yvzBYzUE*-0+TtM3 zb%(@d~1yU3157jaFt7T0N6!8zl0wJ&!#hNMoQf zjpj9`0l;?He9eV#y?HnILklxM*SN(_eP@@sxdSLPBhOS)v(aYZAA+Z&wOG$}Y-5to zFFzTeRM!CqA+B+go$656HE~*;5ADo_cFu=(1DbdwhAnCeC&-PZs8-Q}}NI|5?F_i&w^p6tN1j+h@)E6mgz zRM5NII*a#eZ^DpXBzgxlMF-FG58NEz@mH>E*?qvlyD$3Z>%+PF@HZSCF%$m*djvwY literal 0 HcmV?d00001 diff --git a/sales/migrations/__pycache__/__init__.cpython-312.pyc b/sales/migrations/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c23e04bb224c768fa0c185a05bfaea3b55f2700 GIT binary patch literal 130 zcmX@j%ge<81Wr#TWrFC(AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxdrKq1+P@rF&n3Gzp zpPQLplvt9PpI59OAD@|*SrQ+wS5SG2!zMRBr8Fniu80+=gAs^}L5z>gjEsy$%s>_Z DxY!(Z literal 0 HcmV?d00001 diff --git a/sales/models.py b/sales/models.py new file mode 100644 index 0000000..9cca7d3 --- /dev/null +++ b/sales/models.py @@ -0,0 +1,83 @@ +from django.db import models +from hr.models import Employee + +class Customer(models.Model): + name = models.CharField(max_length=255, verbose_name="顧客名") + code = models.CharField(max_length=50, unique=True, verbose_name="顧客コード") + email = models.EmailField(blank=True, null=True, verbose_name="メールアドレス") + phone = models.CharField(max_length=20, blank=True, null=True, verbose_name="電話番号") + address = models.TextField(blank=True, null=True, verbose_name="住所") + + class Meta: + verbose_name = "顧客" + verbose_name_plural = "顧客" + + def __str__(self): + return self.name + +class Product(models.Model): + name = models.CharField(max_length=255, verbose_name="商品名") + code = models.CharField(max_length=50, unique=True, verbose_name="商品コード") + price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="単価") + description = models.TextField(blank=True, null=True, verbose_name="説明") + + class Meta: + verbose_name = "商品" + verbose_name_plural = "商品" + + def __str__(self): + return self.name + +class Order(models.Model): + STATUS_CHOICES = ( + ('estimate', '見積'), + ('ordered', '受注'), + ('shipped', '出荷済'), + ('billed', '請求済'), + ('paid', '入金済'), + ('cancelled', 'キャンセル'), + ) + + customer = models.ForeignKey(Customer, on_delete=models.CASCADE, verbose_name="顧客") + employee = models.ForeignKey(Employee, on_delete=models.SET_NULL, null=True, blank=True, verbose_name="担当者") + order_date = models.DateField(auto_now_add=True, verbose_name="受注日") + total_amount = models.DecimalField(max_digits=12, decimal_places=2, default=0, verbose_name="合計金額") + status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='estimate', verbose_name="ステータス") + + class Meta: + verbose_name = "受注" + verbose_name_plural = "受注" + + def __str__(self): + return f"{self.customer} - {self.order_date}" + + def calculate_total(self): + total = sum(item.subtotal for item in self.items.all()) + self.total_amount = total + self.save() + +class OrderItem(models.Model): + order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE, verbose_name="受注") + product = models.ForeignKey(Product, on_delete=models.SET_NULL, null=True, verbose_name="商品") + quantity = models.PositiveIntegerField(default=1, verbose_name="数量") + unit_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="単価") + + @property + def subtotal(self): + return self.quantity * self.unit_price + + class Meta: + verbose_name = "受注明細" + verbose_name_plural = "受注明細" + + def save(self, *args, **kwargs): + if not self.unit_price and self.product: + self.unit_price = self.product.price + super().save(*args, **kwargs) + # 親の合計金額を更新 + self.order.calculate_total() + + def delete(self, *args, **kwargs): + order = self.order + super().delete(*args, **kwargs) + order.calculate_total() diff --git a/sales/tests.py b/sales/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/sales/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/sales/views.py b/sales/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/sales/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/server.log b/server.log new file mode 100644 index 0000000..2443752 --- /dev/null +++ b/server.log @@ -0,0 +1,172 @@ +Watching for file changes with StatReloader +[16/Feb/2026 09:29:57] "HEAD / HTTP/1.1" 200 0 +/app/erp_system/settings.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 09:29:49 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/core/models.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:30:36 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/core/admin.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:30:44 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/erp_system/settings.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:30:49 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/hr/models.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:31:58 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/hr/admin.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:32:07 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/erp_system/settings.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:32:14 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/sales/models.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:33:07 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/sales/admin.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:33:20 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/erp_system/settings.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:33:29 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/inventory/models.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:34:29 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/inventory/models.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:34:42 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/inventory/admin.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:34:53 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +/app/erp_system/urls.py changed, reloading. +Performing system checks... + +System check identified no issues (0 silenced). +February 16, 2026 - 18:34:59 +Django version 6.0.2, using settings 'erp_system.settings' +Starting development server at http://127.0.0.1:8000/ +Quit the server with CONTROL-C. + +WARNING: This is a development server. Do not use it in a production setting. Use a production WSGI or ASGI server instead. +For more information on production servers see: https://docs.djangoproject.com/en/6.0/howto/deployment/ +Watching for file changes with StatReloader +[16/Feb/2026 18:38:05] "GET / HTTP/1.1" 200 4218 +[16/Feb/2026 18:40:09] "GET / HTTP/1.1" 200 4218 diff --git a/test_hello_0718.py b/test_hello_0718.py index bf1f44a..71fe400 100644 --- a/test_hello_0718.py +++ b/test_hello_0718.py @@ -1,16 +1,18 @@ import unittest from hello_0718 import hello_0718 + class TestHello0718(unittest.TestCase): def test_hello_0718(self): result = hello_0718() self.assertEqual(result, "hello 0718") - + def test_hello_0718_output(self): # Test that the function returns the expected string expected = "hello 0718" actual = hello_0718() self.assertEqual(actual, expected) + if __name__ == "__main__": - unittest.main() \ No newline at end of file + unittest.main()