From 4e1ef7c230e9688f6d0781f8be8595d1082daf1c Mon Sep 17 00:00:00 2001 From: Akira Date: Fri, 5 Sep 2025 16:57:18 +0900 Subject: [PATCH] add automatic entry script --- .../import_results_None_20250905_162344.csv | 1 + .../import_results_None_20250905_162613.csv | 1 + .../import_results_None_20250905_162727.csv | 1 + .../import_results_None_20250905_163055.csv | 1 + .../import_results_None_20250905_164643.csv | 25 + .../import_results_None_20250905_165633.csv | 28 + CPLIST/input/teams2025.csv | 53 ++ CPLIST/input/teams2025_test.csv | 4 + CPLIST/input/test_trial.csv | 4 + TEAM_CSV_IMPORT_MANUAL.md | 245 ++++++++ rog/management/__init__.py | 1 + rog/management/commands/__init__.py | 1 + rog/management/commands/import_teams.py | 548 ++++++++++++++++++ .../0002_add_competition_status_fields.py | 0 エントリー.md | 34 ++ サーバーAPI変更要求書20250905.md | 104 ++++ 16 files changed, 1051 insertions(+) create mode 100644 CPLIST/input/import_results_None_20250905_162344.csv create mode 100644 CPLIST/input/import_results_None_20250905_162613.csv create mode 100644 CPLIST/input/import_results_None_20250905_162727.csv create mode 100644 CPLIST/input/import_results_None_20250905_163055.csv create mode 100644 CPLIST/input/import_results_None_20250905_164643.csv create mode 100644 CPLIST/input/import_results_None_20250905_165633.csv create mode 100644 CPLIST/input/teams2025.csv create mode 100644 CPLIST/input/teams2025_test.csv create mode 100644 CPLIST/input/test_trial.csv create mode 100644 TEAM_CSV_IMPORT_MANUAL.md create mode 100644 rog/management/__init__.py create mode 100644 rog/management/commands/__init__.py create mode 100644 rog/management/commands/import_teams.py create mode 100644 rog/migrations/0002_add_competition_status_fields.py create mode 100644 エントリー.md create mode 100644 サーバーAPI変更要求書20250905.md diff --git a/CPLIST/input/import_results_None_20250905_162344.csv b/CPLIST/input/import_results_None_20250905_162344.csv new file mode 100644 index 0000000..7fccfd1 --- /dev/null +++ b/CPLIST/input/import_results_None_20250905_162344.csv @@ -0,0 +1 @@ +チーム名,ゼッケン番号,カテゴリー,時間,オーナーメール,メンバー数,メンバー一覧,参加登録状況,エントリーID,作成日時 diff --git a/CPLIST/input/import_results_None_20250905_162613.csv b/CPLIST/input/import_results_None_20250905_162613.csv new file mode 100644 index 0000000..7fccfd1 --- /dev/null +++ b/CPLIST/input/import_results_None_20250905_162613.csv @@ -0,0 +1 @@ +チーム名,ゼッケン番号,カテゴリー,時間,オーナーメール,メンバー数,メンバー一覧,参加登録状況,エントリーID,作成日時 diff --git a/CPLIST/input/import_results_None_20250905_162727.csv b/CPLIST/input/import_results_None_20250905_162727.csv new file mode 100644 index 0000000..7fccfd1 --- /dev/null +++ b/CPLIST/input/import_results_None_20250905_162727.csv @@ -0,0 +1 @@ +チーム名,ゼッケン番号,カテゴリー,時間,オーナーメール,メンバー数,メンバー一覧,参加登録状況,エントリーID,作成日時 diff --git a/CPLIST/input/import_results_None_20250905_163055.csv b/CPLIST/input/import_results_None_20250905_163055.csv new file mode 100644 index 0000000..1b8c133 --- /dev/null +++ b/CPLIST/input/import_results_None_20250905_163055.csv @@ -0,0 +1 @@ +チーム名,ゼッケン番号,カテゴリー,時間,オーナーメール,リーダー,メンバー数,メンバー一覧,参加登録状況,エントリーID,作成日時 diff --git a/CPLIST/input/import_results_None_20250905_164643.csv b/CPLIST/input/import_results_None_20250905_164643.csv new file mode 100644 index 0000000..30e6d0c --- /dev/null +++ b/CPLIST/input/import_results_None_20250905_164643.csv @@ -0,0 +1,25 @@ +チーム名,ゼッケン番号,カテゴリー,時間,オーナーメール,リーダー,メンバー数,メンバー一覧,参加登録状況,エントリーID,作成日時 +いなりずし,1,一般-3時間,3.0時間,いなりずし_member_1@dummy.local,児玉優美(1976-12-13),5,優美(1976-12-13); 豊久(1973-11-23); 児玉優美(1976-12-13); 児玉豊久(1973-11-23); 田中広美(1975-10-31),完了,548,2025-09-05 07:46:39 +Go to the peak!,2,一般-5時間,5.0時間,go_to_the_peak_member_1@dummy.local,柴山晋太郎(1974-12-14),3,柴山晋太郎(1974-12-14); 後藤克弘(1968-04-07); 二村修(1967-06-22),完了,549,2025-09-05 07:46:40 +きみこうじ,3,一般-3時間,3.0時間,きみこうじ_member_1@dummy.local,齋藤貴美子(1980-07-06),2,齋藤貴美子(1980-07-06); 江口浩次(1968-04-19),完了,550,2025-09-05 07:46:40 +ウエストサイド,4,一般-5時間,5.0時間,ウエストサイド_member_1@dummy.local,後藤睦子(1961-05-01),8,睦子(2000-01-01); マサトシ(2000-01-01); ショウコ(2000-01-01); ヨシミ(2000-01-01); 後藤睦子(1961-05-01); 後藤正寿(1959-07-23); 大坪照子(1958-11-11); 松村芳美(1964-04-28),完了,551,2025-09-05 07:46:40 +ベル,5,一般-3時間,3.0時間,ベル_member_1@dummy.local,川村健一(1969-10-08),7,健一(2000-01-01); ショウジ(2000-01-01); チナミ(2000-01-01); 川村健一(1969-10-08); 曽我部知奈美(1973-12-17); 伊藤徳幸(1975-02-06); 筒井勝児(1976-05-31),完了,552,2025-09-05 07:46:40 +ぐりと愉快な仲間たち,6,一般-3時間,3.0時間,ぐりと愉快な仲間たち_member_1@dummy.local,長屋香代子(1961-10-27),4,(1961-10-27); (1961-05-26); 長屋香代子(1961-10-27); 長屋宣宏(1961-05-26),完了,553,2025-09-05 07:46:40 +坂本555,7,一般-5時間,5.0時間,坂本555_member_1@dummy.local,坂本正憲(1972-05-30),3,坂本正憲(1972-05-30); 坂本彩子(1976-03-29); 坂本瑠璃子(2003-08-23),完了,554,2025-09-05 07:46:40 +M sisters with D,8,一般-5時間,5.0時間,m__sisters_with__d_member_1@dummy.local,前田貴代美(1973-01-15),2,前田貴代美(1973-01-15); 中濱智恵美(1969-06-16),完了,555,2025-09-05 07:46:41 +さなっく,9,一般-5時間,5.0時間,さなっく_member_1@dummy.local,山田朋博(1971-04-23),2,山田朋博(1971-04-23); 眞田尚亮(1982-11-30),完了,556,2025-09-05 07:46:41 +煮込みラーメン,10,一般-3時間,3.0時間,煮込みラーメン_member_1@dummy.local,西岡嵩倫(1999-01-05),4,(1999-01-05); (1971-02-02); 西岡嵩倫(1999-01-05); 西岡影忠(1971-02-02),完了,557,2025-09-05 07:46:41 +サウナとビリヤニ,11,一般-3時間,3.0時間,サウナとビリヤニ_member_1@dummy.local,坂口祐生(1992-01-07),3,坂口祐生(1992-01-07); 近藤準(1987-01-25); 圓山大貴(1993-05-10),完了,558,2025-09-05 07:46:41 +ひろ君と愉快な仲間たち,12,お試し・一般-3時間,3.0時間,ひろ君と愉快な仲間たち_member_1@dummy.local,山脇裕子(1984-01-26),5,山脇裕子(1984-01-26); 高橋美智子(1975-04-21); 樋口博久(1964-01-08); 雨宮功治(1962-05-25); 広瀬貴士(1978-08-17),完了,559,2025-09-05 07:46:41 +山下和乃,13,女性ソロ-3時間,3.0時間,山下和乃_member_1@dummy.local,山下和乃(2004-04-26),1,山下和乃(2004-04-26),完了,560,2025-09-05 07:46:42 +Best Wishes,14,女性ソロ-5時間,5.0時間,best_wishes_member_1@dummy.local,長谷川美貴(1973-05-06),2,美貴(1973-05-06); 長谷川美貴(1973-05-06),完了,561,2025-09-05 07:46:42 +しーくん,15,男性ソロ-3時間,3.0時間,しーくん_member_1@dummy.local,水門茂(1962-12-24),2,茂(1962-12-24); 水門茂(1962-12-24),完了,562,2025-09-05 07:46:42 +風呂の会,16,男性ソロ-5時間,5.0時間,風呂の会_member_1@dummy.local,浅井貴弘(1984-07-11),2,貴弘(2000-01-01); 浅井貴弘(1984-07-11),完了,563,2025-09-05 07:46:42 +近藤隆,17,男性ソロ-5時間,5.0時間,近藤隆_member_1@dummy.local,近藤隆(1962-06-28),1,近藤隆(1962-06-28),完了,564,2025-09-05 07:46:42 +日吉将大,18,男性ソロ-3時間,3.0時間,日吉将大_member_1@dummy.local,日吉将大(1995-09-14),2,(1995-09-14); 日吉将大(1995-09-14),完了,565,2025-09-05 07:46:42 +東京OLクラブ,19,男性ソロ-3時間,3.0時間,東京olクラブ_member_1@dummy.local,阿部昌隆(1956-04-20),1,阿部昌隆(1956-04-20),完了,566,2025-09-05 07:46:42 +Best Wishes,20,男性ソロ-5時間,5.0時間,best_wishes_member_1@dummy.local,長谷川美貴(1973-05-06),2,寿郎(1973-10-26); 長谷川美貴(1973-05-06),完了,567,2025-09-05 07:46:42 +脇屋貴司,21,男性ソロ-5時間,5.0時間,脇屋貴司_member_1@dummy.local,脇屋貴司(1983-10-26),1,脇屋貴司(1983-10-26),完了,568,2025-09-05 07:46:42 +うぱうぱアイランド,22,ファミリー-3時間,3.0時間,うぱうぱアイランド_member_1@dummy.local,伊藤由美子(1992-03-28),3,伊藤由美子(1992-03-28); 伊藤嘉仁(1993-08-25); 伊藤嘉利(2022-09-13),完了,569,2025-09-05 07:46:42 +Team117,23,ファミリー-3時間,3.0時間,team117_member_1@dummy.local,佐々木孝好(1970-12-20),4,佐々木孝好(1970-12-20); 佐々木享子(1977-08-25); 佐々木実希(2012-01-21); 佐々木麻妃(2016-07-01),完了,570,2025-09-05 07:46:43 +チームしぇいや,24,ファミリー-3時間,3.0時間,チームしぇいや_member_1@dummy.local,山本龍也(1976-03-14),6,聖也(2009-09-09); 輝也(2015-06-03); 龍也(1976-03-14); 山本龍也(1976-03-14); 山本聖也(2009-09-09); 山本輝也(2015-06-03),完了,571,2025-09-05 07:46:43 diff --git a/CPLIST/input/import_results_None_20250905_165633.csv b/CPLIST/input/import_results_None_20250905_165633.csv new file mode 100644 index 0000000..d76d201 --- /dev/null +++ b/CPLIST/input/import_results_None_20250905_165633.csv @@ -0,0 +1,28 @@ +チーム名,ゼッケン番号,カテゴリー,時間,オーナーメール,リーダー,メンバー数,メンバー一覧,参加登録状況,エントリーID,作成日時 +いなりずし,1,一般-3時間,3.0時間,いなりずし_member_1@dummy.local,児玉優美(1976-12-13),5,優美(1976-12-13); 豊久(1973-11-23); 児玉優美(1976-12-13); 児玉豊久(1973-11-23); 田中広美(1975-10-31),完了,548,2025-09-05 07:46:39 +Go to the peak!,2,一般-5時間,5.0時間,go_to_the_peak_member_1@dummy.local,柴山晋太郎(1974-12-14),3,柴山晋太郎(1974-12-14); 後藤克弘(1968-04-07); 二村修(1967-06-22),完了,549,2025-09-05 07:46:40 +きみこうじ,3,一般-3時間,3.0時間,きみこうじ_member_1@dummy.local,齋藤貴美子(1980-07-06),2,齋藤貴美子(1980-07-06); 江口浩次(1968-04-19),完了,550,2025-09-05 07:46:40 +ウエストサイド,4,一般-5時間,5.0時間,ウエストサイド_member_1@dummy.local,後藤睦子(1961-05-01),8,睦子(2000-01-01); マサトシ(2000-01-01); ショウコ(2000-01-01); ヨシミ(2000-01-01); 後藤睦子(1961-05-01); 後藤正寿(1959-07-23); 大坪照子(1958-11-11); 松村芳美(1964-04-28),完了,551,2025-09-05 07:46:40 +ベル,5,一般-3時間,3.0時間,ベル_member_1@dummy.local,川村健一(1969-10-08),7,健一(2000-01-01); ショウジ(2000-01-01); チナミ(2000-01-01); 川村健一(1969-10-08); 曽我部知奈美(1973-12-17); 伊藤徳幸(1975-02-06); 筒井勝児(1976-05-31),完了,552,2025-09-05 07:46:40 +ぐりと愉快な仲間たち,6,一般-3時間,3.0時間,ぐりと愉快な仲間たち_member_1@dummy.local,長屋香代子(1961-10-27),4,(1961-10-27); (1961-05-26); 長屋香代子(1961-10-27); 長屋宣宏(1961-05-26),完了,553,2025-09-05 07:46:40 +坂本555,7,一般-5時間,5.0時間,坂本555_member_1@dummy.local,坂本正憲(1972-05-30),3,坂本正憲(1972-05-30); 坂本彩子(1976-03-29); 坂本瑠璃子(2003-08-23),完了,554,2025-09-05 07:46:40 +M sisters with D,8,一般-5時間,5.0時間,m__sisters_with__d_member_1@dummy.local,前田貴代美(1973-01-15),2,前田貴代美(1973-01-15); 中濱智恵美(1969-06-16),完了,555,2025-09-05 07:46:41 +さなっく,9,一般-5時間,5.0時間,さなっく_member_1@dummy.local,山田朋博(1971-04-23),2,山田朋博(1971-04-23); 眞田尚亮(1982-11-30),完了,556,2025-09-05 07:46:41 +煮込みラーメン,10,一般-3時間,3.0時間,煮込みラーメン_member_1@dummy.local,西岡嵩倫(1999-01-05),4,(1999-01-05); (1971-02-02); 西岡嵩倫(1999-01-05); 西岡影忠(1971-02-02),完了,557,2025-09-05 07:46:41 +サウナとビリヤニ,11,一般-3時間,3.0時間,サウナとビリヤニ_member_1@dummy.local,坂口祐生(1992-01-07),3,坂口祐生(1992-01-07); 近藤準(1987-01-25); 圓山大貴(1993-05-10),完了,558,2025-09-05 07:46:41 +ひろ君と愉快な仲間たち,12,お試し・一般-3時間,3.0時間,ひろ君と愉快な仲間たち_member_1@dummy.local,山脇裕子(1984-01-26),5,山脇裕子(1984-01-26); 高橋美智子(1975-04-21); 樋口博久(1964-01-08); 雨宮功治(1962-05-25); 広瀬貴士(1978-08-17),完了,559,2025-09-05 07:46:41 +山下和乃,13,女性ソロ-3時間,3.0時間,山下和乃_member_1@dummy.local,山下和乃(2004-04-26),1,山下和乃(2004-04-26),完了,560,2025-09-05 07:46:42 +Best Wishes,14,女性ソロ-5時間,5.0時間,best_wishes_member_1@dummy.local,長谷川美貴(1973-05-06),2,美貴(1973-05-06); 長谷川美貴(1973-05-06),完了,561,2025-09-05 07:46:42 +しーくん,15,男性ソロ-3時間,3.0時間,しーくん_member_1@dummy.local,水門茂(1962-12-24),2,茂(1962-12-24); 水門茂(1962-12-24),完了,562,2025-09-05 07:46:42 +風呂の会,16,男性ソロ-5時間,5.0時間,風呂の会_member_1@dummy.local,浅井貴弘(1984-07-11),2,貴弘(2000-01-01); 浅井貴弘(1984-07-11),完了,563,2025-09-05 07:46:42 +近藤隆,17,男性ソロ-5時間,5.0時間,近藤隆_member_1@dummy.local,近藤隆(1962-06-28),1,近藤隆(1962-06-28),完了,564,2025-09-05 07:46:42 +日吉将大,18,男性ソロ-3時間,3.0時間,日吉将大_member_1@dummy.local,日吉将大(1995-09-14),2,(1995-09-14); 日吉将大(1995-09-14),完了,565,2025-09-05 07:46:42 +東京OLクラブ,19,男性ソロ-3時間,3.0時間,東京olクラブ_member_1@dummy.local,阿部昌隆(1956-04-20),1,阿部昌隆(1956-04-20),完了,566,2025-09-05 07:46:42 +Best Wishes,20,男性ソロ-5時間,5.0時間,best_wishes_member_1@dummy.local,長谷川美貴(1973-05-06),2,寿郎(1973-10-26); 長谷川美貴(1973-05-06),完了,567,2025-09-05 07:46:42 +脇屋貴司,21,男性ソロ-5時間,5.0時間,脇屋貴司_member_1@dummy.local,脇屋貴司(1983-10-26),1,脇屋貴司(1983-10-26),完了,568,2025-09-05 07:46:42 +うぱうぱアイランド,22,ファミリー-3時間,3.0時間,うぱうぱアイランド_member_1@dummy.local,伊藤由美子(1992-03-28),3,伊藤由美子(1992-03-28); 伊藤嘉仁(1993-08-25); 伊藤嘉利(2022-09-13),完了,569,2025-09-05 07:46:42 +Team117,23,ファミリー-3時間,3.0時間,team117_member_1@dummy.local,佐々木孝好(1970-12-20),4,佐々木孝好(1970-12-20); 佐々木享子(1977-08-25); 佐々木実希(2012-01-21); 佐々木麻妃(2016-07-01),完了,570,2025-09-05 07:46:43 +チームしぇいや,24,ファミリー-3時間,3.0時間,チームしぇいや_member_1@dummy.local,山本龍也(1976-03-14),6,聖也(2009-09-09); 輝也(2015-06-03); 龍也(1976-03-14); 山本龍也(1976-03-14); 山本聖也(2009-09-09); 山本輝也(2015-06-03),完了,571,2025-09-05 07:46:43 +まゆちー,25,お試し-3時間,3.0時間,まゆちー_member_1@dummy.local,浅田舞子(1986-02-22),4,浅田舞子(1986-02-22); 浅田真結菜(2014-03-30); 森美紀(1988-03-06); 森千晴(2017-08-04),完了,572,2025-09-05 07:56:33 +ガンバルゾー,26,お試し-3時間,3.0時間,ガンバルゾー_member_1@dummy.local,森祐貴(1985-09-26),4,森祐貴(1985-09-26); 浅田直之(1987-12-12); 浅田晃汰(2014-01-06); 森光喜(2015-04-22),完了,573,2025-09-05 07:56:33 +ランエンジョン!,27,お試し-5時間,5.0時間,ランエンジョン!_member_1@dummy.local,河合賢次(1972-12-14),2,河合賢次(1972-12-14); 中野真樹(1973-01-23),完了,574,2025-09-05 07:56:33 diff --git a/CPLIST/input/teams2025.csv b/CPLIST/input/teams2025.csv new file mode 100644 index 0000000..08cc2f2 --- /dev/null +++ b/CPLIST/input/teams2025.csv @@ -0,0 +1,53 @@ +部門別数,時間,部門,チーム名,メール,パスワード,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3,氏名4,誕生日4,氏名5,誕生日5,氏名6,誕生日6,氏名7,誕生日7,, +1,3,一般,いなりずし,takuyuna1123@icloud.com,ko1703,09014701703,児玉優美,1976/12/13,児玉豊久,1973/11/23,田中広美,1975/10/31,,,,,,,,,, +1,5,一般,Go to the peak!,shibashintan@c.vodafone.ne.jp,shi0145,090-8499-0145,柴山晋太郎,1974/12/14,後藤克弘,1968/04/07,二村修,1967/06/22,,,,,,,,,, +2,3,一般,きみこうじ,chibi-kimi.706@ezweb.ne.jp,sa8309,09062518309,齋藤貴美子,1980/07/06,江口浩次,1968/04/19,,,,,,,,,,,, +2,5,一般,ウエストサイド,chikachan-5101414@i.softbank.jp,go7471,09047997471,後藤睦子,1961/5/1,後藤正寿,1959/7/23,大坪照子,1958/11/11,松村芳美,1964/4/28,,,,,,,, +3,3,一般,ベル,kekomura1008@yahoo.co.jp,ka3001,090-3564-3001,川村健一,1969/10/08,曽我部知奈美,1973/12/17,伊藤徳幸,1975/02/06 ,筒井勝児,1976/05/31,,,,,,,, +3,5,一般,ランエンジョン!,baycools16@gmail.com,ka9749,090÷4790÷9749,河合賢次,1972/12/14,中野真樹,1973/01/23,,,,,,,,,,,, +4,3,一般,ぐりと愉快な仲間たち,kayochu.v.mame.526@icloud.com,na6547,090-1564-6547,長屋香代子,1961/10/27,長屋宣宏,1961/5/26,,,,,,,,,,,, +4,5,一般,坂本555,sakamoto180909@yahoo.co.jp,sa4396,090-8480-4396,坂本正憲,1972/5/30,坂本彩子,1976/3/29,坂本瑠璃子,2003/8/23,,,,,,,,,, +5,3,一般,リキとりんごてぃー,apple1977tea@yahoo.co.jp,te1499,08051241499,鄭寛子,1977/6/13,鄭昌彦,1971/5/26,,,,,,,,,,,, +5,5,一般,East Field,ryo1hi@outlook.com,hi0504,070-8564-0504,東野遼一,1983/09/27,東野智子,1977/03/16,,,,,,,,,,,, +6,3,一般,としちんかずちん,kazu-chin1998@docomo.ne.jp,shi9127,080-2616-9127,渋谷和広,1970/8/1,渋谷敏江,1956/6/16,,,,,,,,,,,, +6,5,一般,M sisters with D,m.kiyomi.115@gmail.com,ma3731,090-4869-3731,前田貴代美,1973/01/15,中濱智恵美,1969/06/16,,,,,,,,,,,, +7,3,一般,シマエナガ,c6d6.lpbm5-s@ezweb.ne.jp,shi1925,090-6336-1925,神谷孫斗,1997/03/02,小栗彩瑚,2001/9/21,,,,,,,,,,,, +7,5,一般,さなっく,santa04230722@icloud.com,ya7192,070-5640-7192,山田朋博,1971/04/23,眞田尚亮,1982/11/30,,,,,,,,,,,, +8,3,一般,煮込みラーメン,t.nishioka1575tt@gmail.com,ni9354,080-8523-9354,西岡嵩倫,1999/1/5,西岡影忠,1971/2/2,,,,,,,,,,,, +9,3,一般,そうたとなゆ,hmt.sota@gmail.com,ho6594,090-1109-6594,甫本創太,1991/06/07,後藤菜友,1994/02/22,,,,,,,,,,,, +10,3,一般,KOJ,balccitomatochop@gmail.com,to5670,090-2181-5670,轟原功樹,1978/08/10,田中美樹,1978/09/07,,,,,,,,,,,, +11,3,一般,サウナとビリヤニ,bitter_smile107@yahoo.co.jp,sa9007,090-4760-9007,坂口祐生,1992/1/7,近藤準,1987/1/25,圓山大貴,1993/5/10,,,,,,,,,, +1,3,お試し・一般,ひろ君と愉快な仲間たち,y0126k@yahoo.co.jp,ya7467,090-9902-7467,山脇裕子,1984/1/26,高橋美智子,1975/04/21,樋口博久,1964/01/08,雨宮功治,1962/05/25,広瀬貴士,1978/08/17,,,,,, +2,3,お試し・一般,フクニシ,appleorange100pct@yahoo.co.jp,fu2792,080-6954-2792,福西直之,1986/2/5,福西愛,1986/3/2,,,,,,,,,,,, +3,3,お試し・一般,あやみち,h613-y5m9t-mich@ezweb.ne.jp,ya3144,090-4447-3144,谷許文音,2006/07/26,谷許美千代,1976/03/27,,,,,,,,,,,, +1,3,お試し・男性ソロ,松村覚司,happy.dreams.come.true923@gmail.com,ma3625,090-8186-3625,松村覚司,1967/9/23,,,,,,,,,,,,,, +2,3,お試し・男性ソロ,高野清司,wakano_528@yahoo.co.jp,ta5865,090-5603-5865,高野清司,71歳,,,,,,,,,,,,,, +1,3,お試し・ファミリー,まゆちー,takoyaki_sena@icloud.com,a1246,090-6090-1246,浅田舞子,1986/02/22,浅田真結菜,2014/03/30,森美紀,1988/03/06,森千晴,2017/8/4,,,,,,,, +1,5,お試し・ファミリー,ポエドリ,takagitoshihiro8@yahoo.co.jp,ta4245,090-5866-4245,高木俊裕,1984/03/09,,,,,,,,,,,,,, +2,3,お試し・ファミリー,ガンバルゾー,youkeymr.01@gmail.com,mo6605,090-6080-6605,森祐貴,1985/9/26,浅田直之,1987/12/12,浅田晃汰,2014/01/06,森光喜,2015/4/22,,,,,,,, +2,5,お試し・ファミリー,fun!fun!うごchan,fulayota333@gmail.com,ha7384,090-6599-7384,早川宏美,1975/6/15,,,,,,,,,,,,,, +3,3,お試し・ファミリー,チームT,sphin28420@aim.com,te1882,080-6709-1882,寺田剛,1979/06/04,寺田恭子,1985/01/10,寺田向希,2023/11/08,,,,,,,,,, +1,3,女性ソロ,山下和乃,kazjamster@gmail.com,ya2450,090-4229-2450,山下和乃,2004/4/26,,,,,,,,,,,,,, +1,5,女性ソロ,Best Wishes,thunderhead_56@yahoo.co.jp,ha7226,090-5652-7226,長谷川美貴,1973/5/6,,,,,,,,,,,,,, +1,3,男性ソロ,しーくん,redleif57917913@ezweb.ne.jp,mi6827,090-2946-6827,水門茂,1962/12/24,,,,,,,,,,,,,, +1,5,男性ソロ,風呂の会,1845dondon@gmail.com,a9050,09096369050,浅井貴弘,1984/07/11,,,,,,,,,,,,,, +2,3,男性ソロ,野田達男,tatchi.sat111@docomo.ne.jp,no0873,0901417-0873,野田達男,1950/9/14,,,,,,,,,,,,,, +2,5,男性ソロ,近藤隆,kondo2000gt@yahoo.ne.jp,ko0666,09018300666,近藤隆,1962/6/28,,,,,,,,,,,,,, +3,3,男性ソロ,日吉将大,hiyomasa0034@gmail.com,hi6343,080-2733-6343,日吉将大,1995/09/14,,,,,,,,,,,,,, +3,5,男性ソロ,松野昌紀,matsubottkuri11994730@gmail.com,ma2606,090-1272-2606,松野昌紀,1972/9/30,,,,,,,,,,,,,, +4,3,男性ソロ,東京OLクラブ,abe_1755_31@yahoo.co.jp,a7102,090-2203-7102,阿部昌隆,1956/4/20,,,,,,,,,,,,,, +4,5,男性ソロ,白木稔人,amida48gan@icloud.com,shi6048,090-7302-6048,白木稔人,1972/5/17,,,,,,,,,,,,,, +5,3,男性ソロ,大阪OLC,t.okiura1961@gmail.com,o1141,090-7888-1141,沖浦徹二,1961/4/29,,,,,,,,,,,,,, +5,5,男性ソロ,Best Wishes,jovi_bounce14@yahoo.co.jp,ko0716,090−3284−0716,小林寿郎,1973/10/26,,,,,,,,,,,,,, +6,3,男性ソロ,つるまいOLC,junhagi68@gmail.com,ha1001,080-3159-1001,萩原淳,1968/3/17,,,,,,,,,,,,,, +6,5,男性ソロ,脇屋貴司,takarinkuririn@gmail.com,wa2659,080-3508-2659,脇屋貴司,1983/10/26,,,,,,,,,,,,,, +7,3,男性ソロ,㈱大垣ケーブルテレビ,so-kishida@ogaki-tv.co.jp,ki1207,0584-82-1207,岸田爽,2001/8/12,,,,,,,,,,,,,, +7,5,男性ソロ,前川一彦,yoshino-chuo@docomo.ne.jp,ma2351,090-1074-2351,前川一彦,不明,,,,,,,,,,,,,, +8,3,男性ソロ,㈱大垣ケーブルテレビ,ta-shiba@ogaki-tv.co.jp,shi1207,,芝建,1998/11/9,,,,,,,,,,,,,, +1,3,ファミリー,うぱうぱアイランド,serukasu@gmail.com,i4200,09084584200,伊藤由美子,19920328,伊藤嘉仁,19930825,伊藤嘉利,20220913,,,,,,,,,, +1,5,ファミリー,ながれぼし,h2798723ddwyus@i.softbank.jp,ta8317,090-1782-8317,高田めぐみ,1982/4/28,高田志穂,2013/12/5,,,,,,,,,,,, +2,3,ファミリー,Team117,miki.maki0107@gmail.com,sa3915,090-7678-3915,佐々木孝好,1970/12/20,佐々木享子,1977/8/25,佐々木実希,2012/1/21,佐々木麻妃,2016/7/1,,,,,,,, +2,5,ファミリー,500えん,roumnet@yahoo.co.jp,go6814,090-9890-6814,五百木弘道,1972/4/29,五百木芽彩,2015/3/13,,,,,,,,,,,, +3,3,ファミリー,チームしぇいや,rayrain3000@docomo.ne.jp,ya2905,090-3056-2905,山本龍也,1976/3/14,山本聖也,2009/9/9,山本輝也,2015/6/3,,,,,,,,,, +3,5,ファミリー,チームユズ,livertish_v.g.35@docomo.ne.jp,ko7822,090-7311-7822,小出龍,1983/2/27,小出柚希,2019/1/7,,,,,,,,,,,, +4,3,ファミリー,Y'sファミリー,inukisen@gmail.com,ya1285,09042581285,安田千穂,1984/3/7,安田尚広,1978/1/18,安田雫,2014/9/2,安田葵,2018/5/13,,,,,,,, \ No newline at end of file diff --git a/CPLIST/input/teams2025_test.csv b/CPLIST/input/teams2025_test.csv new file mode 100644 index 0000000..a8f64bf --- /dev/null +++ b/CPLIST/input/teams2025_test.csv @@ -0,0 +1,4 @@ +部門別数,時間,部門,チーム名,メール,パスワード,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3,氏名4,誕生日4,氏名5,誕生日5,氏名6,誕生日6,氏名7,誕生日7,, +1,3,一般,いなりずし,takuyuna1123@icloud.com,ko1703,09014701703,児玉優美,1976/12/13,児玉豊久,1973/11/23,田中広美,1975/10/31,,,,,,,,,, +1,5,一般,Go to the peak!,shibashintan@c.vodafone.ne.jp,shi0145,090-8499-0145,柴山晋太郎,1974/12/14,後藤克弘,1968/04/07,二村修,1967/06/22,,,,,,,,,, +2,3,一般,きみこうじ,chibi-kimi.706@ezweb.ne.jp,sa8309,09062518309,齋藤貴美子,1980/07/06,江口浩次,1968/04/19,,,,,,,,,,,, diff --git a/CPLIST/input/test_trial.csv b/CPLIST/input/test_trial.csv new file mode 100644 index 0000000..cdbe814 --- /dev/null +++ b/CPLIST/input/test_trial.csv @@ -0,0 +1,4 @@ +部門別数,時間,部門,チーム名,メール,パスワード,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3,氏名4,誕生日4,氏名5,誕生日5,氏名6,誕生日6,氏名7,誕生日7,, +3,3,お試し・ファミリー,まゆちー,takoyaki_sena@icloud.com,ma0222,090-3309-0222,浅田舞子,1986/02/22,浅田真結菜,2014/03/30,森美紀,1988/03/06,森千晴,2017/8/4,,,,,,,, +4,3,お試し・ファミリー,ガンバルゾー,youkeymr.01@gmail.com,mo3540,090-8962-3540,森祐貴,1985/9/26,浅田直之,1987/12/12,浅田晃汰,2014/01/06,森光喜,2015/4/22,,,,,,,, +7,5,お試し,ランエンジョン!,baycools16@gmail.com,ka9749,090÷4790÷9749,河合賢次,1972/12/14,中野真樹,1973/01/23,,,,,,,,,,,, diff --git a/TEAM_CSV_IMPORT_MANUAL.md b/TEAM_CSV_IMPORT_MANUAL.md new file mode 100644 index 0000000..ab2bb3f --- /dev/null +++ b/TEAM_CSV_IMPORT_MANUAL.md @@ -0,0 +1,245 @@ +# チームCSVインポート機能 操作マニュアル + +## 概要 +このマニュアルは、CSVファイルからチーム登録データを一括インポートする機能の使用方法を説明します。 + +## 機能概要 +- CSVファイルからチーム情報を一括読み込み +- ユーザー、チーム、メンバー、エントリーの自動作成 +- リーダー(氏名1)の自動設定 +- イベント参加登録の自動処理 +- カテゴリー自動選択(NewCategoryデータベース参照) +- インポート結果のCSV出力 + +## 前提条件 + +### 1. Docker環境 +```bash +# Dockerコンテナが起動していることを確認 +docker compose ps + +# 起動していない場合 +docker compose up -d +``` + +### 2. イベント作成 +インポート前に対象イベントがデータベースに存在している必要があります。 + +```bash +# イベント存在確認 +docker compose exec app python manage.py shell -c " +from rog.models import NewEvent2 +events = NewEvent2.objects.all() +for event in events: + print(f'イベントコード: {event.event_code}, 名前: {event.event_name}') +" +``` + +## CSVファイル形式 + +### 必須列 +| 列名 | 説明 | 例 | +|------|------|-----| +| 部門別数 | 部門番号 | 1 | +| 時間 | 競技時間 | 3, 5 | +| 部門 | 部門名 | 一般, ファミリー | +| チーム名 | チーム名 | いなりずし | +| メール | 代表者メールアドレス | test@example.com | +| パスワード | ログインパスワード | password123 | +| 電話番号 | 代表者電話番号 | 090-1234-5678 | +| 氏名1 | 代表者氏名(リーダー) | 山田太郎 | +| 誕生日1 | 代表者誕生日 | 1990/4/15 | + +### オプション列 +| 列名 | 説明 | +|------|------| +| 氏名2〜氏名7 | 追加メンバー氏名 | +| 誕生日2〜誕生日7 | 追加メンバー誕生日 | + +### CSVファイル例 +```csv +部門別数,時間,部門,チーム名,メール,パスワード,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3 +1,3,一般,いなりずし,test@example.com,pass123,090-1234-5678,山田太郎,1990/4/15,山田花子,1992/8/20,田中次郎,1988/12/3 +``` + +## 操作手順 + +### 1. ドライラン実行(推奨) +実際のデータ変更前に、処理内容を確認します。 + +```bash +docker compose exec app python manage.py import_teams \ + --event_code="岐阜ロゲイニング2025" \ + --csv_file="CPLIST/input/teams2025.csv" \ + --dry_run +``` + +**出力例:** +``` +[DRY RUN] 行 2: チーム=いなりずし + ユーザー既存: test@example.com パスワード:既存 + エントリー: ゼッケン1, カテゴリー:一般, 時間:3時間 + 参加登録: 新規作成予定 + メンバー: 3名 [山田太郎(1990/4/15), 山田花子(1992/8/20), 田中次郎(1988/12/3)] +``` + +### 2. 本実行 +ドライランで問題がないことを確認後、実際のインポートを実行します。 + +```bash +docker compose exec app python manage.py import_teams \ + --event_code="岐阜ロゲイニング2025" \ + --csv_file="CPLIST/input/teams2025.csv" +``` + +## コマンドパラメータ + +| パラメータ | 必須 | 説明 | 例 | +|-----------|------|------|-----| +| --event_code | ✓ | 対象イベントコード | "岐阜ロゲイニング2025" | +| --csv_file | ✓ | CSVファイルパス | "CPLIST/input/teams2025.csv" | +| --dry_run | - | ドライラン実行 | (パラメータのみ) | + +## 処理内容詳細 + +### 1. ユーザー登録 +- **既存ユーザー**: メールアドレスで検索し、既存の場合は再利用 +- **新規ユーザー**: メール、パスワード、電話番号で新規作成 + +### 2. チーム登録 +- **既存チーム**: 同一オーナー・同一チーム名の場合は再利用 +- **新規チーム**: チーム名、オーナー、イベント情報で新規作成 + +### 3. メンバー登録 +- **リーダー設定**: 氏名1の人を自動的にチームオーナー(リーダー)に設定 +- **追加メンバー**: 氏名2〜氏名7の人をメンバーとして登録 +- **ダミーユーザー**: メンバー用に自動生成されるダミーアカウント + +### 4. エントリー登録 +- **カテゴリー選択**: NewCategoryデータベースから最適なカテゴリーを自動選択 +- **ゼッケン番号**: 自動採番(既存の最大番号+1) +- **重複チェック**: 同一チーム・同一イベントの重複登録を防止 + +## カテゴリー自動選択ロジック + +1. **完全一致**: `部門名-時間時間`(例:一般-3時間) +2. **部分一致**: 部門名と時間が一致し、メンバー数条件を満たすもの +3. **新規作成**: 該当なしの場合は新規カテゴリー作成 + +**既存カテゴリー例:** +- 一般-3時間(最大7名) +- 一般-5時間(最大7名) +- ファミリー-3時間(最大7名) +- ファミリー-5時間(最大7名) +- 男子ソロ-3時間(最大1名) +- 女子ソロ-5時間(最大1名) + +## 出力ファイル + +### CSV結果ファイル +実行完了後、以下の形式でCSVファイルが出力されます: + +**ファイル名:** `import_results_{イベントコード}_{タイムスタンプ}.csv` +**場所:** CSVファイルと同じディレクトリ + +**出力項目:** +- チーム名 +- ゼッケン番号 +- カテゴリー +- 時間 +- オーナーメール +- リーダー(氏名と誕生日) +- メンバー数 +- メンバー一覧 +- 参加登録状況 +- エントリーID +- 作成日時 + +## エラー処理 + +### よくあるエラー + +#### 1. イベントが見つからない +``` +エラー: イベントコード '存在しないイベント' が見つかりません +``` +**対処法:** 正しいイベントコードを確認してください。 + +#### 2. CSVファイルが見つからない +``` +エラー: CSVファイル 'ファイルパス' が見つかりません +``` +**対処法:** ファイルパスを確認してください。 + +#### 3. カテゴリー制約エラー +``` +エラー: このカテゴリーはソロ参加のみ可能です +``` +**対処法:** メンバー数とカテゴリーの制約を確認してください。 + +### エラー出力例 +``` +エラー数: 3 + 行 2: メールアドレスが必要です + 行 5: チーム名が必要です + 行 8: このカテゴリーはソロ参加のみ可能です +``` + +## データ確認方法 + +### インポート結果確認 +```bash +# エントリー確認 +docker compose exec app python manage.py shell -c " +from rog.models import Entry, NewEvent2 +event = NewEvent2.objects.get(event_code='岐阜ロゲイニング2025') +entries = Entry.objects.filter(event=event) +print(f'総エントリー数: {entries.count()}') +for entry in entries[:5]: # 最初の5件 + print(f'ゼッケン{entry.zekken_number}: {entry.team.team_name} ({entry.category.category_name})') +" + +# チーム・メンバー確認 +docker compose exec app python manage.py shell -c " +from rog.models import Team, Member +teams = Team.objects.filter(event__event_code='岐阜ロゲイニング2025') +print(f'総チーム数: {teams.count()}') +for team in teams[:3]: # 最初の3チーム + members = team.members.all() + print(f'チーム: {team.team_name} (リーダー: {team.owner.firstname})') + print(f' メンバー数: {members.count()}') + for member in members: + print(f' - {member.firstname}') +" +``` + +## 注意事項 + +1. **バックアップ**: 本実行前に必ずデータベースのバックアップを取得してください +2. **重複実行**: 同じCSVファイルを複数回実行すると重複データが作成される可能性があります +3. **文字エンコーディング**: CSVファイルはUTF-8で保存してください +4. **メールアドレス**: 重複不可のため、既存ユーザーと重複しないよう注意してください +5. **カテゴリー制約**: NewCategoryの設定(メンバー数制限等)に従います + +## トラブルシューティング + +### Q: インポートが途中で止まる +A: エラーメッセージを確認し、該当行のデータを修正してください。 + +### Q: ゼッケン番号が重複する +A: 既存エントリーを削除してから再実行してください。 + +### Q: カテゴリーが正しく選択されない +A: NewCategoryデータベースの設定を確認してください。 + +### Q: メンバーが登録されない +A: CSVの列名が正しいか(氏名1、氏名2等)確認してください。 + +## サポート + +技術的な問題や質問がある場合は、システム開発チームまでお問い合わせください。 + +--- +**作成日:** 2025年9月5日 +**バージョン:** 1.0 +**対象システム:** 岐阜ロゲイニングサーバー diff --git a/rog/management/__init__.py b/rog/management/__init__.py new file mode 100644 index 0000000..6385696 --- /dev/null +++ b/rog/management/__init__.py @@ -0,0 +1 @@ +# Django management module diff --git a/rog/management/commands/__init__.py b/rog/management/commands/__init__.py new file mode 100644 index 0000000..702fa7c --- /dev/null +++ b/rog/management/commands/__init__.py @@ -0,0 +1 @@ +# Django management commands module diff --git a/rog/management/commands/import_teams.py b/rog/management/commands/import_teams.py new file mode 100644 index 0000000..df70c52 --- /dev/null +++ b/rog/management/commands/import_teams.py @@ -0,0 +1,548 @@ +""" +CSVファイルからチームエントリーをインポートするDjango管理コマンド +CPLIST/input/teams2025.csv 本番用対応 + +Usage: + docker compose exec app python manage.py import_teams --event_code=岐阜ロゲイニング2025 --csv_file=CPLIST/input/teams2025.csv + +Author: システム開発チーム +Date: 2025-09-05 +""" + +import csv +import os +import logging +import re +from datetime import datetime, timedelta +from django.core.management.base import BaseCommand, CommandError +from django.db import transaction, models +from django.contrib.auth.hashers import make_password +from django.utils import timezone +from django.core.exceptions import ValidationError + +from rog.models import ( + CustomUser, Team, Member, Entry, NewEvent2, NewCategory +) + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = 'CSVファイルからチームエントリーをインポート' + + def add_arguments(self, parser): + parser.add_argument( + '--event_code', + type=str, + required=True, + help='インポート先のイベントコード' + ) + parser.add_argument( + '--csv_file', + type=str, + default='CPLIST/input/teams2025.csv', + help='インポートするCSVファイルのパス (default: CPLIST/input/teams2025.csv)' + ) + parser.add_argument( + '--dry_run', + action='store_true', + help='実際にはデータベースに書き込まずに処理を確認' + ) + + def handle(self, *args, **options): + event_code = options['event_code'] + csv_file = options['csv_file'] + dry_run = options['dry_run'] + + self.stdout.write( + self.style.SUCCESS(f'CSVインポート開始: event_code={event_code}, csv_file={csv_file}, dry_run={dry_run}') + ) + + # イベントの存在確認 + try: + event = NewEvent2.objects.get(event_name=event_code) + self.stdout.write(f'イベント見つかりました: {event.event_name} (ID: {event.id})') + except NewEvent2.DoesNotExist: + raise CommandError(f'イベントが見つかりません: {event_code}') + + # CSVファイルの存在確認 + if not os.path.exists(csv_file): + raise CommandError(f'CSVファイルが見つかりません: {csv_file}') + + # 統計情報 + stats = { + 'total_rows': 0, + 'users_created': 0, + 'users_existing': 0, + 'teams_created': 0, + 'members_created': 0, + 'entries_created': 0, + 'errors': [] + } + + try: + with open(csv_file, 'r', encoding='utf-8-sig') as f: # BOM対応のためutf-8-sigを使用 + reader = csv.DictReader(f) + + for row_num, row in enumerate(reader, start=2): # ヘッダー行の次から開始 + stats['total_rows'] += 1 + + try: + if dry_run: + self.process_row_dry_run(row, event, stats, row_num) + else: + with transaction.atomic(): + self.process_row(row, event, stats, row_num) + except Exception as e: + error_msg = f'行 {row_num}: {str(e)}' + stats['errors'].append(error_msg) + self.stdout.write(self.style.ERROR(error_msg)) + continue + + except Exception as e: + raise CommandError(f'CSVファイル読み込みエラー: {str(e)}') + + # 結果レポート + self.print_stats(stats, dry_run) + + # CSV出力 + if not dry_run: + self.export_results_to_csv(event, options['csv_file']) + + def export_results_to_csv(self, event, input_csv_file): + """インポート結果をCSVファイルに出力""" + # 出力ファイル名を生成 + input_dir = os.path.dirname(input_csv_file) + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + output_file = os.path.join(input_dir, f'import_results_{event.event_code}_{timestamp}.csv') + + try: + with open(output_file, 'w', newline='', encoding='utf-8-sig') as csvfile: + fieldnames = [ + 'チーム名', 'ゼッケン番号', 'カテゴリー', '時間', + 'オーナーメール', 'リーダー', 'メンバー数', 'メンバー一覧', + '参加登録状況', 'エントリーID', '作成日時' + ] + writer = csv.DictWriter(csvfile, fieldnames=fieldnames) + writer.writeheader() + + # イベントのエントリーを取得 + entries = Entry.objects.filter(event=event).select_related( + 'team', 'category', 'owner' + ).prefetch_related('team__members__user') + + for entry in entries: + # メンバー一覧を作成 + member_list = [] + for member in entry.team.members.all(): + member_info = f"{member.user.firstname}" + if member.user.date_of_birth: + member_info += f"({member.user.date_of_birth})" + member_list.append(member_info) + + # リーダー情報を取得(チームオーナー) + leader_name = "" + if entry.team.owner: + leader_name = f"{entry.team.owner.firstname}" + if entry.team.owner.date_of_birth: + leader_name += f"({entry.team.owner.date_of_birth})" + + writer.writerow({ + 'チーム名': entry.team.team_name, + 'ゼッケン番号': entry.zekken_number, + 'カテゴリー': entry.category.category_name if entry.category else '', + '時間': f"{entry.category.duration.total_seconds() // 3600}時間" if entry.category else '', + 'オーナーメール': entry.owner.email, + 'リーダー': leader_name, + 'メンバー数': entry.team.members.count(), + 'メンバー一覧': '; '.join(member_list), + '参加登録状況': '完了', + 'エントリーID': entry.id, + '作成日時': entry.date.strftime('%Y-%m-%d %H:%M:%S') + }) + + self.stdout.write( + self.style.SUCCESS(f'インポート結果をCSVに出力しました: {output_file}') + ) + + except Exception as e: + self.stdout.write( + self.style.ERROR(f'CSV出力エラー: {str(e)}') + ) + + def process_row(self, row, event, stats, row_num): + """CSVの1行を処理(実際にデータベースに書き込み)""" + team_name = row.get('チーム名', '').strip() + self.stdout.write(f'行 {row_num} 処理中: チーム={team_name}') + + # 2-1. カスタムユーザー登録 + user = self.get_or_create_user(row, stats) + + # 2-2. チーム登録 + team = self.create_team(row, user, event, stats) + + # メンバー登録(最大7名) + members = self.create_members(row, team, stats) + + # 2-3. エントリー登録 + entry = self.create_entry(row, team, event, stats) + + self.stdout.write(self.style.SUCCESS(f'行 {row_num} 完了: チーム={team.team_name}')) + + def process_row_dry_run(self, row, event, stats, row_num): + """CSVの1行を処理(ドライラン - データベースには書き込まない)""" + team_name = row.get('チーム名', '').strip() + self.stdout.write(f'[DRY RUN] 行 {row_num}: チーム={team_name}') + + # ユーザーの存在確認のみ + email = row.get('メール', '').strip() + password = row.get('パスワード', '').strip() + if email: + existing_user = CustomUser.objects.filter(email=email).first() + if existing_user: + self.stdout.write(f' ユーザー既存: {email} パスワード:既存') + stats['users_existing'] += 1 + else: + display_password = password if password else 'defaultpassword123' + self.stdout.write(f' ユーザー新規作成予定: {email} パスワード:{display_password}') + stats['users_created'] += 1 + + stats['teams_created'] += 1 + stats['entries_created'] += 1 + + # エントリー情報の表示 + category_name = row.get('部門', '').strip() + duration_str = row.get('時間', '').strip() + + # 予想されるゼッケン番号を計算(ドライラン用) + max_zekken = Entry.objects.filter(event=event).aggregate( + max_zekken=models.Max('zekken_number') + )['max_zekken'] or 0 + predicted_zekken = max_zekken + stats['entries_created'] + + self.stdout.write(f' エントリー: ゼッケン{predicted_zekken}, カテゴリー:{category_name}, 時間:{duration_str}時間') + + # 参加登録状況の確認 + existing_entry = Entry.objects.filter(team__team_name=team_name, event=event).first() + if existing_entry: + self.stdout.write(f' 参加登録: 済み(既存エントリーID: {existing_entry.id})') + else: + self.stdout.write(f' 参加登録: 新規作成予定') + + # メンバー数カウント + member_count = 0 + member_names = [] + for i in range(1, 8): # 最大7名 + # 全角数字を使用 + name_key = f'氏名{chr(0xFF10 + i)}' # 全角数字123...を生成 + name = row.get(name_key, '').strip() + if name: + member_count += 1 + birthday_key = f'誕生日{chr(0xFF10 + i)}' + birthday = row.get(birthday_key, '').strip() + member_names.append(f'{name}({birthday})') + stats['members_created'] += member_count + + self.stdout.write(f' メンバー: {member_count}名 [{", ".join(member_names)}]') + + def get_or_create_user(self, row, stats): + """カスタムユーザーの取得または作成""" + email = row.get('メール', '').strip() + password = row.get('パスワード', '').strip() + phone = row.get('電話番号', '').strip() + + if not email: + raise ValueError('メールアドレスが必要です') + + # 特殊文字のクリーンアップ + email = email.replace('@', '@') + phone = self.clean_phone_number(phone) + + # 既存ユーザーの検索 + user = CustomUser.objects.filter(email=email).first() + if user: + self.stdout.write(f' 既存ユーザー: {email}') + stats['users_existing'] += 1 + return user + + # 新規ユーザー作成 + user = CustomUser.objects.create_user( + email=email, + password=password if password else 'defaultpassword123', + is_active=True + ) + self.stdout.write(f' 新規ユーザー作成: {email}') + stats['users_created'] += 1 + return user + + def clean_phone_number(self, phone): + """電話番号のクリーンアップ""" + if not phone: + return '' + + # 全角文字を半角に変換 + phone = phone.replace('-', '-').replace('÷', '-') + + # 余分な文字を削除 + phone = re.sub(r'[^\d\-]', '', phone) + + return phone + + def create_team(self, row, user, event, stats): + """チームの作成""" + team_name = row.get('チーム名', '').strip() + category_name = row.get('部門', '').strip() + + if not team_name: + raise ValueError('チーム名が必要です') + + # チームの重複チェック(同一ユーザー・同一チーム名) + existing_team = Team.objects.filter(team_name=team_name, owner=user).first() + if existing_team: + self.stdout.write(f' 既存チーム使用: {team_name}') + return existing_team + + team = Team.objects.create( + team_name=team_name, + owner=user, + class_name=category_name, + event=event, # イベントを設定 + created_at=timezone.now() + ) + self.stdout.write(f' 新規チーム作成: {team_name}') + stats['teams_created'] += 1 + return team + + def create_members(self, row, team, stats): + """メンバーの作成(最大7名)""" + members = [] + + for i in range(1, 8): # 最大7名 + # 全角数字を使用 + name_key = f'氏名{chr(0xFF10 + i)}' + birthday_key = f'誕生日{chr(0xFF10 + i)}' + + name = row.get(name_key, '').strip() + birthday_str = row.get(birthday_key, '').strip() + + if not name: + continue + + # 誕生日の解析 + birthday = self.parse_birthday(birthday_str) + + # ダミーメールアドレス生成 + dummy_email = f"{team.team_name.replace(' ', '_').replace('!', '').replace('?', '').lower()}_member_{i}@dummy.local" + + # 既存のダミーユーザーチェック + existing_dummy = CustomUser.objects.filter(email=dummy_email).first() + if existing_dummy: + dummy_user = existing_dummy + else: + # ダミーユーザー作成 + dummy_user = CustomUser.objects.create_user( + email=dummy_email, + password='dummypassword123', + firstname=name, + date_of_birth=birthday, + is_active=True + ) + + # 既存メンバーチェック + existing_member = Member.objects.filter(team=team, user=dummy_user).first() + if existing_member: + member = existing_member + else: + # メンバー作成(1番目の人がリーダー) + member = Member.objects.create( + team=team, + user=dummy_user, + firstname=name, + date_of_birth=birthday + ) + # 1番目の人をチームのオーナーとして設定(リーダーの概念) + if i == 1 and team.owner != dummy_user: + team.owner = dummy_user + team.save() + + stats['members_created'] += 1 + + members.append(member) + self.stdout.write(f' メンバー{i}作成: {name}') + + return members + + def parse_birthday(self, birthday_str): + """誕生日文字列の解析""" + if not birthday_str or birthday_str in ['不明', '']: + return None + + # 年齢のみの場合(例:71歳) + if '歳' in birthday_str: + try: + age = int(birthday_str.replace('歳', '')) + # 現在年から年齢を引いて生年を推定 + birth_year = datetime.now().year - age + return datetime(birth_year, 1, 1).date() + except ValueError: + return None + + # 日付形式の解析 + try: + # YYYY/MM/DD形式 + if '/' in birthday_str: + return datetime.strptime(birthday_str, '%Y/%m/%d').date() + # YYYYMMDD形式 + elif len(birthday_str) == 8 and birthday_str.isdigit(): + return datetime.strptime(birthday_str, '%Y%m%d').date() + # YYYY-MM-DD形式 + elif '-' in birthday_str: + return datetime.strptime(birthday_str, '%Y-%m-%d').date() + except ValueError: + pass + + self.stdout.write(self.style.WARNING(f' 誕生日形式エラー: {birthday_str}')) + return None + + def create_entry(self, row, team, event, stats): + """エントリーの作成""" + category_name = row.get('部門', '').strip() + duration_str = row.get('時間', '').strip() + + # メンバー数を取得 + member_count = team.members.count() + + # カテゴリーの取得または作成 + category = None + if category_name and duration_str: + # 既存のカテゴリーから最適なものを選択 + duration_hours = int(duration_str) if duration_str.isdigit() else 3 + + # お試し部門の判定 + is_trial = 'お試し' in category_name + + if is_trial: + # お試しカテゴリーを検索(時間が一致するもの) + trial_categories = NewCategory.objects.filter( + trial=True, + duration__exact=timedelta(hours=duration_hours) + ).order_by('-num_of_member') # メンバー数が多い順 + + # メンバー数に適したカテゴリーを選択 + for cat in trial_categories: + if cat.num_of_member >= member_count: + category = cat + break + + if not category and trial_categories.exists(): + # 適切なサイズがない場合は最大のお試しカテゴリーを使用 + category = trial_categories.first() + else: + # 1. 完全一致するカテゴリーを探す + full_category_name = f"{category_name}-{duration_hours}時間" + category = NewCategory.objects.filter(category_name=full_category_name).first() + + if not category: + # 2. 部分一致するカテゴリーを探す(時間が一致するもの) + categories = NewCategory.objects.filter( + category_name__icontains=category_name, + duration__exact=timedelta(hours=duration_hours), + trial=False # お試しではないもの + ).order_by('-num_of_member') # メンバー数が多い順 + + # メンバー数に適したカテゴリーを選択 + for cat in categories: + if cat.num_of_member >= member_count: + category = cat + break + + if not category: + # 3. どれも見つからない場合は新規作成(メンバー数を考慮) + max_members = max(7, member_count) # 最低でも現在のメンバー数は受け入れる + full_category_name = f"{category_name}-{duration_hours}時間" + category = NewCategory.objects.create( + category_name=full_category_name, + duration=timedelta(hours=duration_hours), + num_of_member=max_members, + trial=is_trial, # お試し判定を反映 + family='ファミリー' in category_name, # ファミリー判定 + category_number=0 + ) + self.stdout.write(f' 新規カテゴリー作成: {full_category_name} (最大{max_members}名, お試し={is_trial})') + else: + trial_text = ", お試し" if category.trial else "" + self.stdout.write(f' 使用カテゴリー: {category.category_name} (最大{category.num_of_member}名{trial_text})') + + # 重複エントリーチェック + existing_entry = Entry.objects.filter(team=team, event=event).first() + if existing_entry: + self.stdout.write(f' 既存エントリー使用: {team.team_name}') + return existing_entry + + # 最大ゼッケン番号を取得 + max_zekken = Entry.objects.filter(event=event).aggregate( + max_zekken=models.Max('zekken_number') + )['max_zekken'] or 0 + + entry = Entry.objects.create( + team=team, + event=event, + category=category, + owner=team.owner, + zekken_number=max_zekken + 1, + date=timezone.now(), + is_active=True + ) + + self.stdout.write(f' エントリー作成: ゼッケン{entry.zekken_number}') + stats['entries_created'] += 1 + return entry + + # 重複エントリーチェック + existing_entry = Entry.objects.filter(team=team, event=event).first() + if existing_entry: + self.stdout.write(f' 既存エントリー使用: {team.team_name}') + return existing_entry + + # 最大ゼッケン番号を取得 + max_zekken = Entry.objects.filter(event=event).aggregate( + max_zekken=models.Max('zekken_number') + )['max_zekken'] or 0 + + entry = Entry.objects.create( + team=team, + event=event, + category=category, + owner=team.owner, + zekken_number=max_zekken + 1, + date=timezone.now(), + is_active=True + ) + + self.stdout.write(f' エントリー作成: ゼッケン{entry.zekken_number}') + stats['entries_created'] += 1 + return entry + + def print_stats(self, stats, dry_run): + """統計情報の表示""" + mode = '[DRY RUN] ' if dry_run else '' + + self.stdout.write(self.style.SUCCESS('\n' + '='*50)) + self.stdout.write(self.style.SUCCESS(f'{mode}インポート結果')) + self.stdout.write(self.style.SUCCESS('='*50)) + self.stdout.write(f'処理行数: {stats["total_rows"]}') + self.stdout.write(f'ユーザー新規作成: {stats["users_created"]}') + self.stdout.write(f'ユーザー既存利用: {stats["users_existing"]}') + self.stdout.write(f'チーム作成: {stats["teams_created"]}') + self.stdout.write(f'メンバー作成: {stats["members_created"]}') + self.stdout.write(f'エントリー作成: {stats["entries_created"]}') + + if stats['errors']: + self.stdout.write(self.style.ERROR(f'\nエラー数: {len(stats["errors"])}')) + for error in stats['errors']: + self.stdout.write(self.style.ERROR(f' {error}')) + + if dry_run: + self.stdout.write(self.style.WARNING('\n※ ドライランのため、実際のデータは作成されていません')) + else: + self.stdout.write(self.style.SUCCESS('\nインポート完了!')) diff --git a/rog/migrations/0002_add_competition_status_fields.py b/rog/migrations/0002_add_competition_status_fields.py new file mode 100644 index 0000000..e69de29 diff --git a/エントリー.md b/エントリー.md new file mode 100644 index 0000000..69dacd7 --- /dev/null +++ b/エントリー.md @@ -0,0 +1,34 @@ +CPLIST/input/teams2025.csv から、以下の手順でデータベーステーブルに書き込むプログラムを作成しなさい。docker compose 環境 + +CSVは以下の項目を持つ。 + +部門別数,時間,部門,チーム名,メール,パスワード,電話番号,氏名1,誕生日1,氏名2,誕生日2,氏名3,誕生日3,氏名4,誕生日4,氏名5,誕生日5,氏名6,誕生日6,氏名7,誕生日7,, + + +1. 起動パラメータで、event_code を指定する. DBはrogdbを使用。user は admin パスワードは admin123456 ホストは localhost を指定 + +2. CSVを読みこみ、各行ごとに下記の処理を行う。 + +2-1. カスタムユーザー + +# メールアドレスをキーに既存ユーザーを取得 + 検索がヒットしなければ、ユーザー登録する。 + +2-2. チーム登録 + +# 部門・時間・チーム名でチーム登録 +# メンバーを1名ずつ7名まで登録 +## それぞれダミーメアドと名前と生年月日でメンバー登録 + +2-3. エントリー登録 + +# 指定されたイベントにチームを登録する。 + +2-4. イベント参加 + +# 登録したエントリーでイベント登録する。 + +2-5. カスタムユーザーの参加イベント記録 + +# 関連なデータをカスタムユーザーに書き込む + diff --git a/サーバーAPI変更要求書20250905.md b/サーバーAPI変更要求書20250905.md new file mode 100644 index 0000000..3153e71 --- /dev/null +++ b/サーバーAPI変更要求書20250905.md @@ -0,0 +1,104 @@ +# サーバーAPI変更要求書 + +**日付**: 2025年9月5日 +**要求者**: システム開発チーム +**対象API**: 通過履歴承認API + +## 変更概要 + +通過履歴の承認処理において、従来の「承認」に加えて「要訂正(仮発行)」機能を追加するため、APIの拡張を要求します。 + +## 対象API + +### エンドポイント +``` +POST /api/approve_checkin_history +``` + +## 変更内容 + +### 現在のリクエストパラメータ +```json +{ + "event_code": "string", + "zekken_number": "string", + "checkin_ids": [int], + "approval_comment": "string" (optional) +} +``` + +### 変更後のリクエストパラメータ +```json +{ + "event_code": "string", + "zekken_number": "string", + "checkin_ids": [int], + "approval_comment": "string" (optional), + "acc_flag": boolean (optional, new) +} +``` + +### 新規追加パラメータ詳細 + +| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 | +|-------------|---|-----|------------|-----| +| acc_flag | boolean | No | true | 承認フラグ
- `true`: 通常の承認処理(自動印刷実行)
- `false`: 要訂正(仮発行処理) | + +## 処理仕様 + +### acc_flag = true(承認)の場合 +- 従来通りの承認処理を実行 +- サーバー側で自動印刷を実行 +- 承認ステータスを「承認済み」に更新 + +### acc_flag = false(要訂正/仮発行)の場合 +- 仮発行処理を実行 +- 通過訂正依頼の自動印刷を行う。 +- 承認ステータスを「要訂正」または適切なステータスに更新 +- 後で再度承認処理が可能な状態を維持 + +### acc_flagが省略された場合 +- デフォルト値 `true` として処理(従来の承認処理) +- 既存のクライアントとの互換性を保持 + +## レスポンス仕様 + +現在のレスポンス形式を維持し、処理結果に応じてメッセージを調整: + +```json +{ + "status": "OK", + "approved_count": int, + "message": "string" +} +``` + +### メッセージ例 +- 承認時: "通過履歴の承認が完了しました" +- 仮発行時: "通過履歴の仮発行が完了しました" + +## 実装優先度 + +**高**: クライアント側実装完了済み、サーバー側対応待ち + +## 補足事項 + +- 既存のAPIとの互換性を保持すること +- acc_flagパラメータは省略可能とし、省略時は従来の承認処理を実行 +- エラーハンドリングは既存の仕様を継承 +- ログ出力にacc_flagの値を含めることを推奨 + +## 影響範囲 + +- 通過履歴承認API(/api/approve_checkin_history) +- 承認処理ロジック +- 印刷処理の制御 +- 承認ステータス管理 + +## テスト項目 + +1. acc_flag=trueでの承認処理(従来通り) +2. acc_flag=falseでの仮発行処理 +3. acc_flag省略時のデフォルト動作 +4. 不正なacc_flag値のエラーハンドリング +5. 既存クライアントとの互換性確認