`ProfessionService` — CRUD, nom normalizatsiyasi, `active` toggle
Tavsif
Qabul mezonlari (DoD)
4 / 4 bajarildi
-
Faol "Payvandchi" bor ekan `" payvandchi "` yaratishga urinish 409 (aniq kod, DB violation emas) qaytaradi
qa-ep-06-t02-s01 · 1 о аввал
-
`active=false` qilingach o'sha nom bilan yangi kasb yaratish 201 qaytaradi
qa-ep-06-t02-s01 · 1 о аввал
-
Ro'yxat filtri `wage_type=piece_rate` va `is_driver=true` bo'yicha ishlaydi
qa-ep-06-t02-s01 · 1 о аввал
-
Hard-delete metodi/yo'li yo'q (faqat `active` toggle)
qa-ep-06-t02-s01 · 1 о аввал
O'zgargan fayllar
9 ta
-
added
erpbom-backend/src/test/java/uz/erpbom/employees/dto/ProfessionUpdateRequestValidationTest.java -
modified
erpbom-backend/src/test/java/uz/erpbom/employees/service/ProfessionServiceTest.java -
modified
erpbom-backend/src/main/java/uz/erpbom/employees/service/ProfessionService.java -
modified
erpbom-backend/src/main/java/uz/erpbom/employees/mapper/ProfessionMapper.java -
modified
erpbom-backend/src/main/java/uz/erpbom/employees/dto/ProfessionUpdateRequest.java -
modified
erpbom-backend/src/main/java/uz/erpbom/employees/dto/ProfessionCreateRequest.java -
modified
erpbom-backend/src/main/java/uz/erpbom/employees/dto/ProfessionResponse.java -
modified
erpbom-backend/src/main/java/uz/erpbom/employees/repository/ProfessionRepository.java -
modified
erpbom-backend/src/main/java/uz/erpbom/employees/entity/Profession.java
Izoh qoldirish
Tarix
33 yozuv
-
✎
finalize-ep-06 yangiladi
Yangilandi: pr_url
-
💬
qa-ep-06-t02-s01 izoh qoldirdi
QA (qa-EP-06-T02-S01) — QABUL QILINDI. Testlar: flock ostida `mvn -Dtest=ProfessionServiceTest,ProfessionUpdateRequestValidationTest test` → Tests run: 18, Failures: 0, Errors: 0 (BUILD SUCCESS). Ish daraxti toza qoldirildi (git status bo'sh). Mezonlar — har biri mustaqil qayta tasdiqlandi (oldingi is_met=true ga tayanilmadi): - AC2828 — ProfessionService.java:194-200 pre-check (ProfessionRepository.java:26 LOWER(TRIM(name)), faqat active) → BusinessConflictException(DUPLICATE_DICTIONARY_VALUE); test ProfessionServiceTest.java:98-107 aynan shu kodni tekshiradi. DB unique buzilishi ham saveOrThrowDuplicate (:209-215) da ayni kodga aylantiriladi — raw DB violation tashqariga chiqmaydi. - AC2829 — V19__professions.sql:42-44 UNIQUE(lower(btrim(name))) WHERE active; test ProfessionServiceTest.java:110-121. - AC2830 — ProfessionRepository.java:35-50 (AND semantikasi); test :169-182. - AC2831 — employees paketida hard-delete chaqiruvi yo'q (grep toza); deactivate (:165-174) faqat active=false; reflection testi :197-204. Blok sababi (PUT semantikasi) yopilgani alohida tekshirildi: - ProfessionUpdateRequest.java:36-40 — @NotNull Boolean isPicking / @NotNull Boolean isDriver (primitiv boolean EMAS). - ProfessionService.java:131-132 — to'g'ridan-to'g'ri set; "null → joriy qiymatni saqla" mantig'i QOLMAGAN; test :151-164 teskari qiymatlar bilan tasdiqlaydi. - ProfessionCreateRequest.java O'ZGARMAGAN (oxirgi tegilgan commit 56e7776); default:false semantikasi ProfessionService.java:92-93 da; kontrakt diff ab2bdb7 faqat Update sxemasiga tegdi. Kontrakt (openapi/v1/employees.yaml): Create required [name, wage_type] + default false; Update required [name, wage_type, is_picking, is_driver]; Response 8 maydon — DTO'lar bilan aynan mos. Mutatsiya tekshiruvi — 3 ta, har biri O'LDIRILDI, bytecode javap bilan tasdiqlandi: 1. @NotNull (isPicking) olib tashlandi → javap NotNull 15→8, ProfessionUpdateRequestValidationTest 2 failure. 2. normalize(): rawName.strip() → rawName → javap String.strip 1→0, ProfessionServiceTest 2 failure. 3. list() da isDriver→null uzatildi → listFiltersByWageTypeAndIsDriverTogether yiqildi. Har mutatsiyadan keyin git checkout bilan tiklandi; yakuniy baseline qayta yashil. Cross-cutting: barcha service metodlarida @Transactional (o'qishlar readOnly=true); tenant_id/organization_id ustuni yo'q (AR-1); variant_operations.profession_id ga haqiqiy FK (AR-10, V19:64-66); snake_case + ko'plik jadval; soft-delete (active); parol/token log muammosi yo'q. Bloklamaydigan kuzatuvlar (qaytarish sababi EMAS): (a) ProfessionService.java:183 javadoc lower(btrim(name)) deydi, amalda faqat strip() — xatti-harakat TO'G'RI (saqlashda registr saqlanadi, lower faqat solishtirishda), lekin izoh chalg'ituvchi. (b) ProfessionServiceTest da DB qatorlari testlar orasida saqlanadi; ro'yxat testlari page size=100 ga tayanadi — kasblar soni 100 dan oshsa contains/doesNotContain assert'lari mo'rt bo'lishi mumkin. HTTP qatlami (400/401/403, controller) bu barg doirasida emas — EP-06-T02-S02.
-
⇄
qa-ep-06-t02-s01 statusni o'zgartirdi Review → Bajarildi
-
✓
qa-ep-06-t02-s01 qabul mezonini belgiladi
✓ Hard-delete metodi/yo'li yo'q (faqat `active` toggle)
-
✓
qa-ep-06-t02-s01 qabul mezonini belgiladi
✓ Ro'yxat filtri `wage_type=piece_rate` va `is_driver=true` bo'yicha ishlaydi
-
✓
qa-ep-06-t02-s01 qabul mezonini belgiladi
✓ `active=false` qilingach o'sha nom bilan yangi kasb yaratish 201 qaytaradi
-
✓
qa-ep-06-t02-s01 qabul mezonini belgiladi
✓ Faol "Payvandchi" bor ekan `" payvandchi "` yaratishga urinish 409 (aniq kod, DB violation emas) qaytaradi
-
⇄
coder-ep-06-t02-s01 statusni o'zgartirdi Ishlanyapti → Review
-
✎
coder-ep-06-t02-s01 yangiladi
Yangilandi: commit_sha
-
✓
coder-ep-06-t02-s01 qabul mezonini belgiladi
✓ Hard-delete metodi/yo'li yo'q (faqat `active` toggle)
-
✓
coder-ep-06-t02-s01 qabul mezonini belgiladi
✓ Ro'yxat filtri `wage_type=piece_rate` va `is_driver=true` bo'yicha ishlaydi
-
✓
coder-ep-06-t02-s01 qabul mezonini belgiladi
✓ `active=false` qilingach o'sha nom bilan yangi kasb yaratish 201 qaytaradi
-
✓
coder-ep-06-t02-s01 qabul mezonini belgiladi
✓ Faol "Payvandchi" bor ekan `" payvandchi "` yaratishga urinish 409 (aniq kod, DB violation emas) qaytaradi
-
📄
coder-ep-06-t02-s01 fayllarni qayd etdi
4 ta fayl qayd etildi
-
⇄
coder-ep-06-t02-s01 statusni o'zgartirdi Backlog → Ishlanyapti
Agent ishni boshladi
-
⚑
coder-ep-06-t02-s01 ishga oldi
-
⇄
team-lead-pm statusni o'zgartirdi Bloklangan → Backlog
Blok yechildi: biznes egasi qaror qildi — PUT /professions/{id} da is_picking va is_driver MAJBURIY (to liq almashtirish semantikasi). Kontrakt yangilandi: ab2bdb7 (ProfessionUpdateRequest.required + izohlar), mock :4010 tasdiqladi (flagsiz PUT 400). DTO/validatsiya shu bo yicha yozilsin.
-
⇄
qa-ep-06-t02-s01 statusni o'zgartirdi Review → Bloklangan
SPEC/KONTRAKT BO'SHLIG'I: `ProfessionUpdateRequest.is_picking`/`is_driver` berilmasa nima bo'lishi (mavjud qiymat saqlanadimi yoki false ga tushadimi) na kontraktda (openapi/v1/employees.yaml:1508 — `default` yo'q, `nullable` yo'q, izoh yo'q; `ProfessionCreateRequest` da esa `default: false` ATAYLAB bor), na 04_employees §2.2 da belgilangan. Koder o'z talqinini (partial update — ProfessionService.java:129-134) kodga va `updateWithNullFlagsKeepsExistingValue` testiga qotirgan; repo pretsedenti esa teskari tomonga ishora qiladi (WarehouseService.update:113 — majburiy bo'lmagan `location` null bilan TOZALANADI, ya'ni PUT = to'liq almashtirish; barcha muzlatilgan kontraktlarda Update DTO booleanlari `required`). Ta'siri kichik emas: `is_driver` — 09_auth R53 login gate'i va 06_orders R19(a); `is_picking` — 07 R29 `work.claim` gate'i — flagni yubormagan tahrir formasi haydovchi loginini jimgina o'chirishi mumkin. Kerak: erp/ §5 savol-javob sikli (04_employees §2.2) → so'ng 'Kontrakt o'zgarishi' tartibi bilan aniq semantika. QOLGANI SOZ: 4/4 qabul mezoni mustaqil tasdiqlandi, 12/12 test yashil, 3(a) toggle teshigi YO'Q (activate() pre-check + test bor). Batafsil izoh — activity #5499.
-
💬
qa-ep-06-t02-s01 izoh qoldirdi
QA (qa-EP-06-T02-S01) — mustaqil tekshiruv. Testlar: `mvn -Dtest=ProfessionServiceTest test` → **12/12 yashil** (Testcontainers PG16, V1..V23). **Mezonlar — hammasi mustaqil tasdiqlandi (4/4):** - AC2828 — `create()` → `normalize()` → `requireNoDuplicate()` → `ProfessionRepository.findActiveByNormalizedName` (`LOWER(TRIM(p.name)) = LOWER(TRIM(:name)) AND p.active = true`) → `BusinessConflictException("DUPLICATE_DICTIONARY_VALUE")` → `GlobalExceptionHandler:97` → **409 CONFLICT**. Xizmat qatlamidagi pre-check MAVJUD, DB indeksi (`uq_professions_name_active`, V19) — ikkinchi himoya, `saveAndFlush` try/catch ichida. - AC2829 — V19 dagi partial indeks `WHERE active` + test `reusingNameAfterDeactivateSucceeds`. - AC2830 — `ProfessionRepository.search` AND-predikatlari; test manfiy nazorat bilan (`doesNotContain("Shafyor-F2-monthly", "Yuklovchi-F3-notdriver")`) — ikkala filtr ham pinlangan. - AC2831 — butun `uz/erpbom/employees/` bo'ylab hech qanday `delete`/`remove` chaqiruvi yo'q; kontraktda DELETE yo'li yo'q. **3(a) — `active=false → true` toggle teshigi: TESHIK YO'Q.** `ProfessionService.activate()` `save()`dan OLDIN `requireNoDuplicate(profession.getName(), id)` chaqiradi (ProfessionService.java:152) → ayni nomli boshqa faol kasb bo'lsa aniq 409 DUPLICATE_DICTIONARY_VALUE, DataIntegrityViolation emas. Test bor va haqiqiy: `activateReRejectsDuplicateAgainstAnotherActiveProfession` (ProfessionServiceTest.java:196-212) — aynan shu ssenariyni (nofaol qatorni faol kasb nomiga rename → activate) yuritadi. AC2828 mezoni toggle yo'lida ham bajarilgan. **3(b) — `is_picking`/`is_driver` partial-update talqini: SPEC/KONTRAKT BO'SHLIG'I → BLOCKED.** Koder `ProfessionUpdateRequest` da `null` = "mavjud qiymat saqlanadi" deb qaror qildi (ProfessionService.java:129-134) va uni test bilan qotirdi (`updateWithNullFlagsKeepsExistingValue`). Bu qarorni na kontrakt, na spec bermaydi: 1. `openapi/v1/employees.yaml:1508` `ProfessionUpdateRequest` — `required: [name, wage_type]`; `is_picking`/`is_driver` da `default` YO'Q, `nullable: true` YO'Q, izoh YO'Q. Taqqoslash uchun `ProfessionCreateRequest` da ayni maydonlarda `default: false` + "Berilmasa `false`" ATAYLAB yozilgan — ya'ni Update'da bu ongli ravishda olib tashlangan yoki e'tibordan qolgan; qaysi biri ekani yozilmagan. 2. Repo pretsedenti TESKARI tomonga ishora qiladi: butun muzlatilgan kontraktlarda Update DTO'sidagi har bir boolean `required` (`BrandUpdateRequest: [name, active]`, `PriceTypeUpdateRequest`, `WarehouseUpdateRequest: [name, active]`), majburiy bo'lmagan maydon esa to'liq almashtiriladi — `WarehouseService.update():113` `setLocation(request.location())` bilan `null` qiymatni TOZALAYDI (`WarehouseUpdateRequest.location` — `nullable: true`, required emas). Ya'ni bu repo'da PUT = to'liq almashtirish. 3. Spec §2.2 faqat DB ustun defaultini beradi (`NOT NULL DEFAULT false` — INSERT semantikasi), UPDATE'da yo'q maydon nima bo'lishini umuman aytmaydi. 4. T00 kontrakt agenti bunday qarorlarni HAR DOIM hujjatlashtirgan (`EmployeeUpdateRequest.account_user_id`: "`null` — bog'lanish uziladi"; "`active` — `PUT /professions/{id}` tanasida YO'Q") va hatto bitta "⛔ SPEC BO'SHLIG'I" ni ochiq e'lon qilgan. Bu yerda hech narsa yozilmagani — qaror QABUL QILINMAGANI belgisi. Nega bu muhim (ta'siri kichik emas): `is_driver` — 09_auth **R53** login gate'i va 06_orders **R19(a)** `driver_employee_id` biriktirishi; `is_picking` — 07 **R29** `work.claim` gate'i. "To'liq almashtirish" talqinida flagni yubormagan web tahrir formasi haydovchining mobil login huquqini JIMGINA o'chiradi; "saqlanadi" talqinida esa repo konvensiyasi buziladi. Ikkala variant ham biznesga ta'sir qiladi — implementator o'ylab topadigan narsa emas. Kerak: (1) `erp/` §5 savol-javob sikli 04_employees §2.2 bo'yicha; (2) so'ng "Kontrakt o'zgarishi" tartibi bilan `ProfessionUpdateRequest` ga aniq semantika (`required: [name, wage_type, is_picking, is_driver]` — repo konvensiyasi; YOKI `nullable`+izoh bilan partial). Kod va `updateWithNullFlagsKeepsExistingValue` testi shundan keyin moslashtiriladi. **Qo'shimcha topilma — test bo'shlig'i (blokdan alohida, mutatsiya bilan tasdiqlangan).** Kontrakt `ProfessionCreateRequest.name` da "Saqlashdan oldin `btrim` qilinadi" deydi. `ProfessionService.normalize():186` ni `return rawName;` ga o'zgartirdim (mutatsiya) — `javap -c` bilan bytecode qayta kompilyatsiya bo'lgani tasdiqlandi (`aload_1; areturn`, `strip()` chaqiruvi yo'q) — **12/12 test baribir yashil qoldi** (mutant tirik qoldi). Sabab: pre-check SQL o'zi `TRIM()` qiladi, shuning uchun 409 yo'li mutatsiyani sezmaydi; saqlangan nomning trim qilinganini hech bir test tekshirmaydi. Kerak: `create(" Yangi kasb ")` → `response.name()` `"Yangi kasb"` ekanini (va `update` uchun ham) tasdiqlaydigan assert. Fayl mutatsiyadan keyin `git checkout` bilan TIKLANDI (`git status` toza). Cross-cutting: `@Transactional` — 5/5 metodda (o'qish `readOnly = true`) ✓ · `tenant_id`/`organization_id` ustuni yo'q (AR-1) ✓ · soft-delete `active`, fizik DELETE yo'q ✓ · nomlash `snake_case`, jadval ko'plikda ✓ · `is`-prefiksli record komponenti → SNAKE_CASE `is_picking`/`is_driver` (repo konvensiyasi, `StockResponse` naqshi) ✓ · log'da maxfiy ma'lumot yo'q ✓. Eslatma: `RecipesAndRoutesMigrationTest` (EP-02 fixture) qizilligi bu bargga aloqador emas — tegilmadi.
-
✓
qa-ep-06-t02-s01 qabul mezonini belgiladi
✓ Hard-delete metodi/yo'li yo'q (faqat `active` toggle)
-
✓
qa-ep-06-t02-s01 qabul mezonini belgiladi
✓ Ro'yxat filtri `wage_type=piece_rate` va `is_driver=true` bo'yicha ishlaydi
-
✓
qa-ep-06-t02-s01 qabul mezonini belgiladi
✓ `active=false` qilingach o'sha nom bilan yangi kasb yaratish 201 qaytaradi
-
✓
qa-ep-06-t02-s01 qabul mezonini belgiladi
✓ Faol "Payvandchi" bor ekan `" payvandchi "` yaratishga urinish 409 (aniq kod, DB violation emas) qaytaradi
-
⇄
coder-ep-06-t02-s01 statusni o'zgartirdi Ishlanyapti → Review
-
✎
coder-ep-06-t02-s01 yangiladi
Yangilandi: branch, commit_sha
-
✓
coder-ep-06-t02-s01 qabul mezonini belgiladi
✓ Hard-delete metodi/yo'li yo'q (faqat `active` toggle)
-
✓
coder-ep-06-t02-s01 qabul mezonini belgiladi
✓ Ro'yxat filtri `wage_type=piece_rate` va `is_driver=true` bo'yicha ishlaydi
-
✓
coder-ep-06-t02-s01 qabul mezonini belgiladi
✓ `active=false` qilingach o'sha nom bilan yangi kasb yaratish 201 qaytaradi
-
✓
coder-ep-06-t02-s01 qabul mezonini belgiladi
✓ Faol "Payvandchi" bor ekan `" payvandchi "` yaratishga urinish 409 (aniq kod, DB violation emas) qaytaradi
-
📄
coder-ep-06-t02-s01 fayllarni qayd etdi
8 ta fayl qayd etildi
-
⇄
coder-ep-06-t02-s01 statusni o'zgartirdi Backlog → Ishlanyapti
Agent ishni boshladi
-
⚑
coder-ep-06-t02-s01 ishga oldi
-
✦
pm-agent yaratdi
`ProfessionService` — CRUD, nom normalizatsiyasi, `active` toggle
Ma'lumot
- Agent
- coder-ep-06-t02-s01
- Olingan
- 1 о аввал
- Boshlandi
- 24.08.2026 11:38
- Tugadi
- 24.08.2026 13:04
- Baho
- 4 soat
- Spec
- erp/docs/modules/04_employees.md#2.2
- Branch
- feat/EP-06-erpbom-backend
- Commit
- 7f9efcd8ee9e
Bog'liqliklar
Bundan oldin tugashi kerak
Yo'q — bu ish mustaqil.
Agent uchun
Bu ishni AI agent quyidagicha oladi:
curl -s -X POST https://pmboard.ferp.uz/api/items/EP-06-T02-S01/claim \ -H "X-Agent: backend-dev-1"
Tugatgach:
curl -s -X POST https://pmboard.ferp.uz/api/items/EP-06-T02-S01/status \
-H "X-Agent: backend-dev-1" \
-H "Content-Type: application/json" \
-d '{"status":"review","note":"..."}'