Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-05-06 11:07:55 +03:00
parent 05a2a03a6a
commit 77fe2b04b6
38 changed files with 12676 additions and 8 deletions

View File

@@ -23,6 +23,7 @@ UI_DIR=/opt/bssapp/ui/dist
# ===============================
POSTGRES_CONN=host=46.224.33.150 port=5432 user=postgres password=tayitkan dbname=baggib2b sslmode=disable
MSSQL_CONN=sqlserver://sa:Gil_0150@10.0.0.9:1433?database=BAGGI_V3&encrypt=disable
URETIM_MSSQL_CONN=sqlserver://sa:Gil_0150@10.0.0.9:1433?database=URETIM&encrypt=disable
# ===============================
# PDF

0
svc/backend-dev.err.log Normal file
View File

365
svc/backend-dev.out.log Normal file
View File

@@ -0,0 +1,365 @@
time=2026-04-29T21:47:12.721+03:00 level=INFO msg="backend start" app=bssapp-backend scope=main
time=2026-04-29T21:47:12.767+03:00 level=INFO msg="🔥🔥🔥 BSSAPP BACKEND STARTED — LOGIN ROUTE SHOULD EXIST 🔥🔥🔥" app=bssapp-backend
time=2026-04-29T21:47:12.770+03:00 level=INFO msg="🔐 JWT_SECRET yüklendi" app=bssapp-backend
MSSQL baglantisi basarili (connection timeout=120s, dial timeout=120s)
URETIM MSSQL baglantisi basarili (connection timeout=120s, dial timeout=120s)
time=2026-04-29T21:47:13.271+03:00 level=INFO msg="PostgreSQL bağlantısı başarılı" app=bssapp-backend
time=2026-04-29T21:47:13.581+03:00 level=INFO msg="✅ Admin dept permissions seeded" app=bssapp-backend
time=2026-04-29T21:47:13.581+03:00 level=INFO msg="🟢 auditlog Init called, buffer: 1000" app=bssapp-backend
time=2026-04-29T21:47:13.587+03:00 level=INFO msg="🟢 auditlog worker STARTED" app=bssapp-backend
time=2026-04-29T21:47:13.588+03:00 level=INFO msg="🕵️ AuditLog sistemi başlatıldı (buffer=1000)" app=bssapp-backend
time=2026-04-29T21:47:13.678+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE EXTENSION IF NOT EXISTS pg_trgm\"" app=bssapp-backend
time=2026-04-29T21:47:13.765+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_t_key_lang ON mk_translator (t_key, lang_code)\"" app=bssapp-backend
time=2026-04-29T21:47:13.854+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_status_lang_updated ON mk_translator (status, lang_code...\"" app=bssapp-backend
time=2026-04-29T21:47:13.944+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_manual_status ON mk_translator (is_manual, status)\"" app=bssapp-backend
time=2026-04-29T21:47:14.032+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_source_type_expr ON mk_translator ((COALESCE(NULLIF(pro...\"" app=bssapp-backend
time=2026-04-29T21:47:14.133+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_source_text_trgm ON mk_translator USING gin (source_tex...\"" app=bssapp-backend
time=2026-04-29T21:47:14.222+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_translated_text_trgm ON mk_translator USING gin (transl...\"" app=bssapp-backend
time=2026-04-29T21:47:14.223+03:00 level=INFO msg="✉️ Graph Mailer hazır (App-only token) | from=baggiss@baggi.com.tr" app=bssapp-backend
time=2026-04-29T21:47:14.223+03:00 level=INFO msg="✉️ Graph Mailer hazır" app=bssapp-backend
📋 [DEBUG] İlk 10 kullanıcı:
- 1 : ctengiz
- 2 : ali.kale
- 5 : mehmet.keçeci
- 6 : mert.keçeci
- 7 : samet.keçeci
- 9 : orhan.caliskan
- 10 : nilgun.sara
- 14 : rustem.kurbanov
- 15 : caner.akyol
- 16 : kemal.matyakupov
time=2026-04-29T21:47:15.216+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/auth/login [auth:login]" app=bssapp-backend
time=2026-04-29T21:47:16.101+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/auth/refresh [auth:refresh]" app=bssapp-backend
time=2026-04-29T21:47:16.996+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/password/forgot [auth:update]" app=bssapp-backend
time=2026-04-29T21:47:17.904+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/password/reset/validate/{token} [auth:view]" app=bssapp-backend
time=2026-04-29T21:47:18.782+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/password/reset [auth:update]" app=bssapp-backend
time=2026-04-29T21:47:19.673+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/password/change [auth:update]" app=bssapp-backend
time=2026-04-29T21:47:20.563+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/activity-logs [system:read]" app=bssapp-backend
time=2026-04-29T21:47:21.444+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/test-mail [system:update]" app=bssapp-backend
time=2026-04-29T21:47:22.332+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/system/market-mail-mappings/lookups [system:update]" app=bssapp-backend
time=2026-04-29T21:47:23.224+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/system/market-mail-mappings [system:update]" app=bssapp-backend
time=2026-04-29T21:47:24.100+03:00 level=INFO msg="✅ Route+Perm registered → PUT /api/system/market-mail-mappings/{marketId} [system:update]" app=bssapp-backend
time=2026-04-29T21:47:24.978+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/language/translations [language:update]" app=bssapp-backend
time=2026-04-29T21:47:25.870+03:00 level=INFO msg="✅ Route+Perm registered → PUT /api/language/translations/{id} [language:update]" app=bssapp-backend
time=2026-04-29T21:47:26.752+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/language/translations/upsert-missing [language:update]" app=bssapp-backend
time=2026-04-29T21:47:27.638+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/language/translations/sync-sources [language:update]" app=bssapp-backend
time=2026-04-29T21:47:28.520+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/language/translations/translate-selected [language:update]" app=bssapp-backend
time=2026-04-29T21:47:29.449+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/language/translations/bulk-approve [language:update]" app=bssapp-backend
time=2026-04-29T21:47:30.328+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/language/translations/bulk-update [language:update]" app=bssapp-backend
time=2026-04-29T21:47:31.208+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/roles/{id}/permissions [system:update]" app=bssapp-backend
time=2026-04-29T21:47:32.090+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/roles/{id}/permissions [system:update]" app=bssapp-backend
time=2026-04-29T21:47:32.979+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/users/{id}/permissions [system:update]" app=bssapp-backend
time=2026-04-29T21:47:33.884+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users/{id}/permissions [system:update]" app=bssapp-backend
time=2026-04-29T21:47:34.814+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/permissions/routes [system:view]" app=bssapp-backend
time=2026-04-29T21:47:35.718+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/permissions/effective [system:view]" app=bssapp-backend
time=2026-04-29T21:47:36.597+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/permissions/matrix [system:view]" app=bssapp-backend
time=2026-04-29T21:47:37.490+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/role-dept-permissions/list [system:update]" app=bssapp-backend
time=2026-04-29T21:47:38.395+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/roles/{roleId}/departments/{deptCode}/permissions [system:update]" app=bssapp-backend
time=2026-04-29T21:47:39.290+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/roles/{roleId}/departments/{deptCode}/permissions [system:update]" app=bssapp-backend
time=2026-04-29T21:47:40.177+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/users/list [user:view]" app=bssapp-backend
time=2026-04-29T21:47:41.060+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users [user:insert]" app=bssapp-backend
time=2026-04-29T21:47:41.940+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/users/{id} [user:update]" app=bssapp-backend
time=2026-04-29T21:47:42.841+03:00 level=INFO msg="✅ Route+Perm registered → PUT /api/users/{id} [user:update]" app=bssapp-backend
time=2026-04-29T21:47:43.736+03:00 level=INFO msg="✅ Route+Perm registered → DELETE /api/users/{id} [user:delete]" app=bssapp-backend
time=2026-04-29T21:47:44.618+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users/{id}/admin-reset-password [user:update]" app=bssapp-backend
time=2026-04-29T21:47:45.499+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users/{id}/send-password-mail [user:update]" app=bssapp-backend
time=2026-04-29T21:47:46.389+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users/create [user:insert]" app=bssapp-backend
time=2026-04-29T21:47:47.287+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/nebim-users [user:view]" app=bssapp-backend
time=2026-04-29T21:47:48.184+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/piyasalar [user:view]" app=bssapp-backend
time=2026-04-29T21:47:49.074+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/users-perm [user:view]" app=bssapp-backend
time=2026-04-29T21:47:49.968+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/roles-perm [user:view]" app=bssapp-backend
time=2026-04-29T21:47:50.851+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/departments-perm [user:view]" app=bssapp-backend
time=2026-04-29T21:47:52.990+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/modules [user:view]" app=bssapp-backend
time=2026-04-29T21:47:53.893+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/roles [user:view]" app=bssapp-backend
time=2026-04-29T21:47:54.789+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/departments [user:view]" app=bssapp-backend
time=2026-04-29T21:47:55.694+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/accounts [customer:view]" app=bssapp-backend
time=2026-04-29T21:47:56.587+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/customer-list [customer:view]" app=bssapp-backend
time=2026-04-29T21:47:57.474+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/today-currency [finance:view]" app=bssapp-backend
time=2026-04-29T21:47:58.358+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/export-pdf [finance:export]" app=bssapp-backend
time=2026-04-29T21:47:59.303+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/exportstamentheaderreport-pdf [finance:export]" app=bssapp-backend
time=2026-04-29T21:48:00.197+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/customer-balances [finance:view]" app=bssapp-backend
time=2026-04-29T21:48:01.080+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/customer-balances/export-pdf [finance:export]" app=bssapp-backend
time=2026-04-29T21:48:01.968+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/customer-balances/export-excel [finance:export]" app=bssapp-backend
time=2026-04-29T21:48:02.850+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/account-aging-statement [finance:view]" app=bssapp-backend
time=2026-04-29T21:48:03.759+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/account-aging-statement/export-pdf [finance:export]" app=bssapp-backend
time=2026-04-29T21:48:04.664+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/account-aging-statement/export-screen-pdf [finance:export]" app=bssapp-backend
time=2026-04-29T21:48:05.600+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/account-aging-statement/export-excel [finance:export]" app=bssapp-backend
time=2026-04-29T21:48:06.513+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/aged-customer-balance-list [finance:view]" app=bssapp-backend
time=2026-04-29T21:48:07.460+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/statements [finance:view]" app=bssapp-backend
time=2026-04-29T21:48:08.375+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/statements/{id}/details [finance:view]" app=bssapp-backend
time=2026-04-29T21:48:09.258+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/order/create [order:insert]" app=bssapp-backend
time=2026-04-29T21:48:10.154+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/order/update [order:update]" app=bssapp-backend
time=2026-04-29T21:48:11.034+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/order/{id}/bulk-due-date [order:update]" app=bssapp-backend
time=2026-04-29T21:48:11.924+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/order/get/{id} [order:view]" app=bssapp-backend
time=2026-04-29T21:48:12.811+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/list [order:view]" app=bssapp-backend
time=2026-04-29T21:48:13.695+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/production-list [order:update]" app=bssapp-backend
time=2026-04-29T21:48:14.624+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/production-items/cditem-lookups [order:view]" app=bssapp-backend
time=2026-04-29T21:48:15.544+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/production-items/{id} [order:view]" app=bssapp-backend
time=2026-04-29T21:48:17.930+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/orders/production-items/{id}/insert-missing [order:update]" app=bssapp-backend
time=2026-04-29T21:48:18.825+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/orders/production-items/{id}/validate [order:update]" app=bssapp-backend
time=2026-04-29T21:48:20.012+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/orders/production-items/{id}/apply [order:update]" app=bssapp-backend
time=2026-04-29T21:48:20.955+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/close-ready [order:update]" app=bssapp-backend
time=2026-04-29T21:48:21.854+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/orders/bulk-close [order:update]" app=bssapp-backend
time=2026-04-29T21:48:23.037+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/export [order:export]" app=bssapp-backend
time=2026-04-29T21:48:23.994+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/order/check/{id} [order:view]" app=bssapp-backend
time=2026-04-29T21:48:24.943+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/order/validate [order:insert]" app=bssapp-backend
time=2026-04-29T21:48:26.184+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/order/pdf/{id} [order:export]" app=bssapp-backend
time=2026-04-29T21:48:27.066+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/order/send-market-mail [order:read]" app=bssapp-backend
time=2026-04-29T21:48:27.952+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/order-inventory [order:view]" app=bssapp-backend
time=2026-04-29T21:48:28.844+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orderpricelistb2b [order:view]" app=bssapp-backend
time=2026-04-29T21:48:29.747+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/min-price [order:view]" app=bssapp-backend
time=2026-04-29T21:48:30.627+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/products [order:view]" app=bssapp-backend
time=2026-04-29T21:48:31.512+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-detail [order:view]" app=bssapp-backend
time=2026-04-29T21:48:32.407+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-cditem [order:view]" app=bssapp-backend
time=2026-04-29T21:48:33.297+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-colors [order:view]" app=bssapp-backend
time=2026-04-29T21:48:34.190+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-newcolors [order:view]" app=bssapp-backend
time=2026-04-29T21:48:35.380+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-colorsize [order:view]" app=bssapp-backend
time=2026-04-29T21:48:36.265+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-secondcolor [order:view]" app=bssapp-backend
time=2026-04-29T21:48:37.162+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-newsecondcolor [order:view]" app=bssapp-backend
time=2026-04-29T21:48:38.051+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-attributes [order:view]" app=bssapp-backend
time=2026-04-29T21:48:38.944+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-item-attributes [order:view]" app=bssapp-backend
time=2026-04-29T21:48:39.858+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-stock-query [order:view]" app=bssapp-backend
time=2026-04-29T21:48:40.753+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-stock-attribute-options [order:view]" app=bssapp-backend
time=2026-04-29T21:48:41.640+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-stock-query-by-attributes [order:view]" app=bssapp-backend
time=2026-04-29T21:48:42.531+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-images [order:view]" app=bssapp-backend
time=2026-04-29T21:48:43.410+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-images/{id}/content [order:view]" app=bssapp-backend
time=2026-04-29T21:48:44.296+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-size-match/rules [order:view]" app=bssapp-backend
time=2026-04-29T21:48:45.193+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/products [order:view]" app=bssapp-backend
time=2026-04-29T21:48:46.071+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/no-cost-products [order:view]" app=bssapp-backend
time=2026-04-29T21:48:46.982+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-products [order:view]" app=bssapp-backend
time=2026-04-29T21:48:48.168+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-history [order:view]" app=bssapp-backend
time=2026-04-29T21:48:49.052+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-detail-groups [order:view]" app=bssapp-backend
time=2026-04-29T21:48:49.942+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-detail-header [order:view]" app=bssapp-backend
time=2026-04-29T21:48:50.846+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/production-types [order:view]" app=bssapp-backend
time=2026-04-29T21:48:51.740+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/detail-editor-options [order:view]" app=bssapp-backend
time=2026-04-29T21:48:52.639+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates [order:view]" app=bssapp-backend
time=2026-04-29T21:48:53.538+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-detail-line-history [order:view]" app=bssapp-backend
time=2026-04-29T21:48:54.426+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-detail-similar-history [order:view]" app=bssapp-backend
time=2026-04-29T21:48:55.308+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/pricing/production-product-costing/has-cost-detail-bulk-prices [order:view]" app=bssapp-backend
time=2026-04-29T21:48:56.205+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/roles [user:view]" app=bssapp-backend
time=2026-04-29T21:48:57.093+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/departments [user:view]" app=bssapp-backend
time=2026-04-29T21:48:57.980+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/piyasalar [user:view]" app=bssapp-backend
time=2026-04-29T21:49:00.122+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/roles/{id}/departments [user:update]" app=bssapp-backend
time=2026-04-29T21:49:01.048+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/roles/{id}/piyasalar [user:update]" app=bssapp-backend
time=2026-04-29T21:49:01.970+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users/{id}/roles [user:update]" app=bssapp-backend
time=2026-04-29T21:49:03.170+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/admin/users/{id}/piyasa-sync [admin:user.update]" app=bssapp-backend
time=2026-04-29T21:49:03.172+03:00 level=INFO msg="🌍 CORS Allowed Origin: http://ss.baggi.com.tr/app" app=bssapp-backend
time=2026-04-29T21:49:03.172+03:00 level=INFO msg="🚀 Server running at: 0.0.0.0:8080" app=bssapp-backend
time=2026-04-29T21:49:03.172+03:00 level=INFO msg="🕓 Translation sync next run at 2026-04-30T04:00:00+03:00 (in 6h10m57s)" app=bssapp-backend
time=2026-04-29T21:57:23.596+03:00 level=INFO msg="➡️ POST /api/auth/refresh | auth=false" app=bssapp-backend
time=2026-04-29T21:57:24.523+03:00 level=INFO msg="⬅️ POST /api/auth/refresh | status=200 | 927.7384ms" app=bssapp-backend
time=2026-04-29T21:57:24.524+03:00 level=INFO msg="⚠️ LOGGER: claims is NIL" app=bssapp-backend
time=2026-04-29T21:57:24.524+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=<nil> actor_user=<nil> role=public nav /api/auth/refresh target=<nil>" app=bssapp-backend
time=2026-04-29T21:57:24.544+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:57:24.545+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-header | auth=true" app=bssapp-backend
time=2026-04-29T21:57:24.546+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:57:24.546+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-groups | auth=true" app=bssapp-backend
time=2026-04-29T21:57:24.546+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-header" app=bssapp-backend
time=2026-04-29T21:57:24.546+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-groups" app=bssapp-backend
time=2026-04-29T21:57:24.850+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:57:24.850+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/production-types | auth=true" app=bssapp-backend
time=2026-04-29T21:57:24.850+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/production-types" app=bssapp-backend
time=2026-04-29T21:57:24.964+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:57:24.964+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:57:25.021+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:57:25.295+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:57:25.297+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-groups detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211
time=2026-04-29T21:57:25.297+03:00 level=INFO msg="query dispatch" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 query=production-product-costing.no-cost-detail-rows recete_kodu=S001-DMY26211 urun_kodu=S001-DMY26211
time=2026-04-29T21:57:25.300+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:57:25.301+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-header detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211
time=2026-04-29T21:57:25.302+03:00 level=INFO msg="query dispatch" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 query=production-product-costing.no-cost-detail-header recete_kodu=S001-DMY26211 urun_kodu=S001-DMY26211
time=2026-04-29T21:57:25.350+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:57:25.351+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.production-types
time=2026-04-29T21:57:25.389+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-header detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211 n_urt_recete_id=20815 urun_kodu=S001-DMY26211
time=2026-04-29T21:57:25.391+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-header | status=200 | 845.3861ms" app=bssapp-backend
time=2026-04-29T21:57:25.391+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:57:25.391+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-header target=<nil>" app=bssapp-backend
time=2026-04-29T21:57:25.406+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.production-types row_count=4
time=2026-04-29T21:57:25.406+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-groups detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211 group_count=3 row_count=26 scan_errors=0
time=2026-04-29T21:57:25.407+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/production-types | status=200 | 556.5518ms" app=bssapp-backend
time=2026-04-29T21:57:25.409+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:57:25.409+03:00 level=INFO msg="[ProductionNoCostDetailGroups] done recete_kodu=S001-DMY26211 groups=3" app=bssapp-backend
time=2026-04-29T21:57:25.411+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-groups | status=200 | 864.8427ms" app=bssapp-backend
time=2026-04-29T21:57:25.412+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:57:25.567+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/production-types target=<nil>" app=bssapp-backend
time=2026-04-29T21:57:25.733+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-groups target=<nil>" app=bssapp-backend
time=2026-04-29T21:57:26.592+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:57:26.593+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates | auth=true" app=bssapp-backend
time=2026-04-29T21:57:26.593+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-exchange-rates" app=bssapp-backend
time=2026-04-29T21:57:26.758+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:57:27.095+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:57:27.097+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.exchange-rates maliyet_tarihi=2026-04-29
time=2026-04-29T21:57:27.097+03:00 level=INFO msg="[ProductionHasCostDetailExchangeRates] start maliyet_tarihi=2026-04-29" app=bssapp-backend
time=2026-04-29T21:57:27.191+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.exchange-rates rate_date=2026-04-29 usd_rate=45.0515 eur_rate=52.6761 gbp_rate=60.8954
time=2026-04-29T21:57:27.191+03:00 level=INFO msg="[ProductionHasCostDetailExchangeRates] done maliyet_tarihi=2026-04-29 rate_date=2026-04-29 usd=45.0515 eur=52.6761" app=bssapp-backend
time=2026-04-29T21:57:27.191+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates | status=200 | 598.5886ms" app=bssapp-backend
time=2026-04-29T21:57:27.191+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:57:27.191+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-exchange-rates target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:04.959+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:04.961+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-header | auth=true" app=bssapp-backend
time=2026-04-29T21:58:04.961+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:04.961+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-groups | auth=true" app=bssapp-backend
time=2026-04-29T21:58:04.962+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-header" app=bssapp-backend
time=2026-04-29T21:58:04.962+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:04.963+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-groups" app=bssapp-backend
time=2026-04-29T21:58:04.963+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:05.269+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:05.270+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/production-types | auth=true" app=bssapp-backend
time=2026-04-29T21:58:05.271+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/production-types" app=bssapp-backend
time=2026-04-29T21:58:05.271+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:05.353+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:05.355+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-groups detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211
time=2026-04-29T21:58:05.355+03:00 level=INFO msg="query dispatch" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 query=production-product-costing.no-cost-detail-rows recete_kodu=S001-DMY26211 urun_kodu=S001-DMY26211
time=2026-04-29T21:58:05.394+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-groups detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211 group_count=3 row_count=26 scan_errors=0
time=2026-04-29T21:58:05.396+03:00 level=INFO msg="[ProductionNoCostDetailGroups] done recete_kodu=S001-DMY26211 groups=3" app=bssapp-backend
time=2026-04-29T21:58:05.397+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-groups | status=200 | 435.4404ms" app=bssapp-backend
time=2026-04-29T21:58:05.397+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:05.397+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-groups target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:05.432+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:05.433+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-groups | auth=true" app=bssapp-backend
time=2026-04-29T21:58:05.433+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-groups" app=bssapp-backend
time=2026-04-29T21:58:05.433+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:05.652+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:05.653+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.production-types
time=2026-04-29T21:58:05.680+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.production-types row_count=4
time=2026-04-29T21:58:05.681+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/production-types | status=200 | 410.1372ms" app=bssapp-backend
time=2026-04-29T21:58:05.681+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:05.681+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/production-types target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:05.690+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:05.690+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/production-types | auth=true" app=bssapp-backend
time=2026-04-29T21:58:05.691+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/production-types" app=bssapp-backend
time=2026-04-29T21:58:05.691+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:05.943+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:05.944+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-header detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211
time=2026-04-29T21:58:05.944+03:00 level=INFO msg="query dispatch" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 query=production-product-costing.no-cost-detail-header recete_kodu=S001-DMY26211 urun_kodu=S001-DMY26211
time=2026-04-29T21:58:06.066+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:06.067+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.production-types
time=2026-04-29T21:58:06.494+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-header detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211 n_urt_recete_id=20815 urun_kodu=S001-DMY26211
time=2026-04-29T21:58:06.494+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-header | status=200 | 1.5333479s" app=bssapp-backend
time=2026-04-29T21:58:06.495+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:06.495+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-header target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:06.545+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.production-types row_count=4
time=2026-04-29T21:58:06.545+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/production-types | status=200 | 855.4172ms" app=bssapp-backend
time=2026-04-29T21:58:06.546+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:06.667+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/production-types target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:06.751+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:06.752+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-groups detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211
time=2026-04-29T21:58:06.753+03:00 level=INFO msg="query dispatch" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 query=production-product-costing.no-cost-detail-rows recete_kodu=S001-DMY26211 urun_kodu=S001-DMY26211
time=2026-04-29T21:58:06.817+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:06.818+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-header | auth=true" app=bssapp-backend
time=2026-04-29T21:58:06.818+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-header" app=bssapp-backend
time=2026-04-29T21:58:06.819+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:07.050+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-groups detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211 group_count=3 row_count=26 scan_errors=0
time=2026-04-29T21:58:07.050+03:00 level=INFO msg="[ProductionNoCostDetailGroups] done recete_kodu=S001-DMY26211 groups=3" app=bssapp-backend
time=2026-04-29T21:58:07.050+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-groups | status=200 | 1.617361s" app=bssapp-backend
time=2026-04-29T21:58:07.051+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:07.051+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-groups target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:07.183+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:07.183+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-header detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211
time=2026-04-29T21:58:07.184+03:00 level=INFO msg="query dispatch" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 query=production-product-costing.no-cost-detail-header recete_kodu=S001-DMY26211 urun_kodu=S001-DMY26211
time=2026-04-29T21:58:07.213+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-header detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211 n_urt_recete_id=20815 urun_kodu=S001-DMY26211
time=2026-04-29T21:58:07.214+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-header | status=200 | 396.483ms" app=bssapp-backend
time=2026-04-29T21:58:07.214+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:07.242+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-header target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:08.489+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:08.491+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates | auth=true" app=bssapp-backend
time=2026-04-29T21:58:08.491+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-exchange-rates" app=bssapp-backend
time=2026-04-29T21:58:08.492+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:08.823+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:08.823+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.exchange-rates maliyet_tarihi=2026-04-29
time=2026-04-29T21:58:08.823+03:00 level=INFO msg="[ProductionHasCostDetailExchangeRates] start maliyet_tarihi=2026-04-29" app=bssapp-backend
time=2026-04-29T21:58:08.851+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.exchange-rates rate_date=2026-04-29 usd_rate=45.0515 eur_rate=52.6761 gbp_rate=60.8954
time=2026-04-29T21:58:08.853+03:00 level=INFO msg="[ProductionHasCostDetailExchangeRates] done maliyet_tarihi=2026-04-29 rate_date=2026-04-29 usd=45.0515 eur=52.6761" app=bssapp-backend
time=2026-04-29T21:58:08.853+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates | status=200 | 361.9866ms" app=bssapp-backend
time=2026-04-29T21:58:08.853+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:08.853+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-exchange-rates target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:55.938+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:55.939+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-header | auth=true" app=bssapp-backend
time=2026-04-29T21:58:55.939+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-header" app=bssapp-backend
time=2026-04-29T21:58:55.939+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:56.076+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:56.078+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-groups | auth=true" app=bssapp-backend
time=2026-04-29T21:58:56.079+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-groups" app=bssapp-backend
time=2026-04-29T21:58:56.080+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:56.251+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:56.252+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/production-types | auth=true" app=bssapp-backend
time=2026-04-29T21:58:56.252+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/production-types" app=bssapp-backend
time=2026-04-29T21:58:56.252+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:56.269+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:56.270+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-header detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211
time=2026-04-29T21:58:56.270+03:00 level=INFO msg="query dispatch" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 query=production-product-costing.no-cost-detail-header recete_kodu=S001-DMY26211 urun_kodu=S001-DMY26211
time=2026-04-29T21:58:56.297+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-header detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211 n_urt_recete_id=20815 urun_kodu=S001-DMY26211
time=2026-04-29T21:58:56.299+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-header | status=200 | 359.9756ms" app=bssapp-backend
time=2026-04-29T21:58:56.299+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:56.299+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-header target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:56.418+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:56.419+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-groups detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211
time=2026-04-29T21:58:56.419+03:00 level=INFO msg="query dispatch" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 query=production-product-costing.no-cost-detail-rows recete_kodu=S001-DMY26211 urun_kodu=S001-DMY26211
time=2026-04-29T21:58:56.462+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-groups detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211 group_count=3 row_count=26 scan_errors=0
time=2026-04-29T21:58:56.463+03:00 level=INFO msg="[ProductionNoCostDetailGroups] done recete_kodu=S001-DMY26211 groups=3" app=bssapp-backend
time=2026-04-29T21:58:56.463+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-groups | status=200 | 385.19ms" app=bssapp-backend
time=2026-04-29T21:58:56.463+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:56.467+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-groups target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:56.589+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:56.590+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.production-types
time=2026-04-29T21:58:56.598+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.production-types row_count=4
time=2026-04-29T21:58:56.598+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/production-types | status=200 | 346.1189ms" app=bssapp-backend
time=2026-04-29T21:58:56.598+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:56.635+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/production-types target=<nil>" app=bssapp-backend
time=2026-04-29T21:58:57.550+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:58:57.551+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates | auth=true" app=bssapp-backend
time=2026-04-29T21:58:57.552+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-exchange-rates" app=bssapp-backend
time=2026-04-29T21:58:57.553+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:58:57.891+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:58:57.891+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.exchange-rates maliyet_tarihi=2026-04-29
time=2026-04-29T21:58:57.891+03:00 level=INFO msg="[ProductionHasCostDetailExchangeRates] start maliyet_tarihi=2026-04-29" app=bssapp-backend
time=2026-04-29T21:58:57.923+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.exchange-rates rate_date=2026-04-29 usd_rate=45.0515 eur_rate=52.6761 gbp_rate=60.8954
time=2026-04-29T21:58:57.924+03:00 level=INFO msg="[ProductionHasCostDetailExchangeRates] done maliyet_tarihi=2026-04-29 rate_date=2026-04-29 usd=45.0515 eur=52.6761" app=bssapp-backend
time=2026-04-29T21:58:57.925+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates | status=200 | 373.817ms" app=bssapp-backend
time=2026-04-29T21:58:57.925+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:58:57.925+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-exchange-rates target=<nil>" app=bssapp-backend
time=2026-04-29T21:59:35.728+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:59:35.729+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-header | auth=true" app=bssapp-backend
time=2026-04-29T21:59:35.729+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:59:35.730+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-groups | auth=true" app=bssapp-backend
time=2026-04-29T21:59:35.730+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-groups" app=bssapp-backend
time=2026-04-29T21:59:35.730+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:59:35.731+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-header" app=bssapp-backend
time=2026-04-29T21:59:35.731+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:59:35.820+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:59:35.820+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/production-types | auth=true" app=bssapp-backend
time=2026-04-29T21:59:35.821+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/production-types" app=bssapp-backend
time=2026-04-29T21:59:35.821+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:59:36.078+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:59:36.079+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-header detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211
time=2026-04-29T21:59:36.079+03:00 level=INFO msg="query dispatch" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 query=production-product-costing.no-cost-detail-header recete_kodu=S001-DMY26211 urun_kodu=S001-DMY26211
time=2026-04-29T21:59:36.079+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:59:36.079+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-groups detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211
time=2026-04-29T21:59:36.079+03:00 level=INFO msg="query dispatch" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 query=production-product-costing.no-cost-detail-rows recete_kodu=S001-DMY26211 urun_kodu=S001-DMY26211
time=2026-04-29T21:59:36.108+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-header detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211 n_urt_recete_id=20815 urun_kodu=S001-DMY26211
time=2026-04-29T21:59:36.108+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-header | status=200 | 379.6458ms" app=bssapp-backend
time=2026-04-29T21:59:36.108+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:59:36.108+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-header target=<nil>" app=bssapp-backend
time=2026-04-29T21:59:36.161+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:59:36.161+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.production-types
time=2026-04-29T21:59:36.168+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.production-types row_count=4
time=2026-04-29T21:59:36.168+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/production-types | status=200 | 347.978ms" app=bssapp-backend
time=2026-04-29T21:59:36.169+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:59:36.172+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.detail-groups detail_source=no-cost urun_kodu=S001-DMY26211 recete_kodu=S001-DMY26211 group_count=3 row_count=26 scan_errors=0
time=2026-04-29T21:59:36.173+03:00 level=INFO msg="[ProductionNoCostDetailGroups] done recete_kodu=S001-DMY26211 groups=3" app=bssapp-backend
time=2026-04-29T21:59:36.173+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-groups | status=200 | 443.1026ms" app=bssapp-backend
time=2026-04-29T21:59:36.174+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:59:36.276+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/production-types target=<nil>" app=bssapp-backend
time=2026-04-29T21:59:36.441+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-groups target=<nil>" app=bssapp-backend
time=2026-04-29T21:59:37.181+03:00 level=INFO msg="🔐 GLOBAL AUTH user=5 role=admin" app=bssapp-backend
time=2026-04-29T21:59:37.182+03:00 level=INFO msg="➡️ GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates | auth=true" app=bssapp-backend
time=2026-04-29T21:59:37.183+03:00 level=INFO msg="AUTH_MIDDLEWARE PASS user=5 role=admin method=GET path=/api/pricing/production-product-costing/has-cost-detail-exchange-rates" app=bssapp-backend
time=2026-04-29T21:59:37.184+03:00 level=INFO msg="🔐 PERM CHECK user=5 role=3 dept=[UST_YONETIM] order:view" app=bssapp-backend
time=2026-04-29T21:59:37.526+03:00 level=INFO msg=" ↳ ROLE+DEPT OVERRIDE = true" app=bssapp-backend
time=2026-04-29T21:59:37.527+03:00 level=INFO msg="request start" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.exchange-rates maliyet_tarihi=2026-04-29
time=2026-04-29T21:59:37.527+03:00 level=INFO msg="[ProductionHasCostDetailExchangeRates] start maliyet_tarihi=2026-04-29" app=bssapp-backend
time=2026-04-29T21:59:37.566+03:00 level=INFO msg="request done" app=bssapp-backend trace_id=pcd-no-cost-4d8aee0f-e28c-4f5a-b758-1aea1d646a62 handler=production-product-costing.exchange-rates rate_date=2026-04-29 usd_rate=45.0515 eur_rate=52.6761 gbp_rate=60.8954
time=2026-04-29T21:59:37.566+03:00 level=INFO msg="[ProductionHasCostDetailExchangeRates] done maliyet_tarihi=2026-04-29 rate_date=2026-04-29 usd=45.0515 eur=52.6761" app=bssapp-backend
time=2026-04-29T21:59:37.567+03:00 level=INFO msg="⬅️ GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates | status=200 | 384.597ms" app=bssapp-backend
time=2026-04-29T21:59:37.567+03:00 level=INFO msg="✅ LOGGER CLAIMS user=mehmet.keçeci role=admin id=5" app=bssapp-backend
time=2026-04-29T21:59:37.568+03:00 level=INFO msg="🧾 auditlog INSERT | actor_dfusr=5 actor_user=mehmet.keçeci role=admin nav /api/pricing/production-product-costing/has-cost-detail-exchange-rates target=<nil>" app=bssapp-backend

View File

@@ -13,6 +13,7 @@ import (
)
var MssqlDB *sql.DB
var UretimDB *sql.DB
func envInt(name string, fallback int) int {
raw := strings.TrimSpace(os.Getenv(name))
@@ -123,3 +124,37 @@ func ConnectMSSQL() error {
func GetDB() *sql.DB {
return MssqlDB
}
// ConnectMSSQLUretim initializes the URETIM MSSQL connection from environment.
func ConnectMSSQLUretim() error {
connString := strings.TrimSpace(os.Getenv("URETIM_MSSQL_CONN"))
if connString == "" {
return fmt.Errorf("URETIM_MSSQL_CONN tanimli degil")
}
connectionTimeoutSec := envInt("URETIM_MSSQL_CONNECTION_TIMEOUT_SEC", envInt("MSSQL_CONNECTION_TIMEOUT_SEC", 120))
dialTimeoutSec := envInt("URETIM_MSSQL_DIAL_TIMEOUT_SEC", connectionTimeoutSec)
connString = ensureMSSQLTimeouts(connString, connectionTimeoutSec, dialTimeoutSec)
var err error
UretimDB, err = sql.Open("sqlserver", connString)
if err != nil {
return fmt.Errorf("URETIM MSSQL baglanti hatasi: %w", err)
}
UretimDB.SetMaxOpenConns(envInt("URETIM_MSSQL_MAX_OPEN_CONNS", envInt("MSSQL_MAX_OPEN_CONNS", 40)))
UretimDB.SetMaxIdleConns(envInt("URETIM_MSSQL_MAX_IDLE_CONNS", envInt("MSSQL_MAX_IDLE_CONNS", 40)))
UretimDB.SetConnMaxLifetime(time.Duration(envInt("URETIM_MSSQL_CONN_MAX_LIFETIME_MIN", envInt("MSSQL_CONN_MAX_LIFETIME_MIN", 30))) * time.Minute)
UretimDB.SetConnMaxIdleTime(time.Duration(envInt("URETIM_MSSQL_CONN_MAX_IDLE_MIN", envInt("MSSQL_CONN_MAX_IDLE_MIN", 10))) * time.Minute)
if err = UretimDB.Ping(); err != nil {
return fmt.Errorf("URETIM MSSQL erisilemiyor: %w", err)
}
fmt.Printf("URETIM MSSQL baglantisi basarili (connection timeout=%ds, dial timeout=%ds)\n", connectionTimeoutSec, dialTimeoutSec)
return nil
}
func GetUretimDB() *sql.DB {
return UretimDB
}

View File

@@ -8,8 +8,10 @@ import (
"bssapp-backend/permissions"
"bssapp-backend/repository"
"bssapp-backend/routes"
"bssapp-backend/utils"
"database/sql"
"log"
"log/slog"
"net/http"
"os"
"path"
@@ -738,6 +740,101 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductPricingListHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/no-cost-products", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionNoCostProductsHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/has-cost-products", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionHasCostProductsHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/has-cost-history", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionHasCostHistoryHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/has-cost-detail-groups", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionHasCostDetailGroupsHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/has-cost-detail-header", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionHasCostDetailHeaderHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/production-types", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionTypesHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/detail-editor-options", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionHasCostDetailEditorOptionsHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/has-cost-detail-exchange-rates", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionHasCostDetailExchangeRatesHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/has-cost-detail-line-history", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionHasCostDetailLineHistoryHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/has-cost-detail-similar-history", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionHasCostDetailSimilarHistoryHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/has-cost-detail-bulk-prices", "POST",
"order", "view",
wrapV3(http.HandlerFunc(routes.PostProductionHasCostDetailBulkPricesHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/options/urun-ana-grup", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionProductCostingUrunAnaGrupOptionsHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/options/urun-alt-grup", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionProductCostingUrunAltGrupOptionsHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/options/urun-ana-alt-combos", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionProductCostingUrunAnaAltCombosHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/options/mtbolum", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionProductCostingMTBolumOptionsHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/maliyet-parca-eslestirme", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductionProductCostingParcaMappingsHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/maliyet-parca-eslestirme", "DELETE",
"order", "view",
wrapV3(http.HandlerFunc(routes.DeleteProductionProductCostingParcaMappingHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/maliyet-parca-eslestirme/upsert", "POST",
"order", "view",
wrapV3(http.HandlerFunc(routes.PostProductionProductCostingParcaMappingUpsertHandler)),
)
bindV3(r, pgDB,
"/api/pricing/production-product-costing/maliyet-parca-eslestirme/set-active", "POST",
"order", "view",
wrapV3(http.HandlerFunc(routes.PostProductionProductCostingParcaMappingSetActiveHandler)),
)
// ============================================================
// ROLE MANAGEMENT
@@ -797,6 +894,8 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
}
func main() {
utils.InitSlog()
slog.Info("backend start", "scope", "main")
log.Println("🔥🔥🔥 BSSAPP BACKEND STARTED — LOGIN ROUTE SHOULD EXIST 🔥🔥🔥")
// -------------------------------------------------------
@@ -825,6 +924,13 @@ func main() {
log.Fatal(err3)
}
}
if err := db.ConnectMSSQLUretim(); err != nil {
if strings.Contains(err.Error(), "URETIM_MSSQL_CONN tanimli degil") {
log.Println("⚠️ URETIM DB baglantisi atlandi: URETIM_MSSQL_CONN tanimli degil")
} else {
log.Fatal(err)
}
}
pgDB, err := db.ConnectPostgres()
if err != nil {

View File

@@ -0,0 +1,282 @@
package models
type ProductionNoCostProductRow struct {
UretimSekli string `json:"UretimSekli"`
UrtSiparisNo string `json:"nUrtSiparisNo"`
IslemTarihi string `json:"dteIslemTarihi"`
FirmaKodu string `json:"FirmaKodu"`
FirmaAdi string `json:"FirmaAdi"`
SonIsEmriVeren string `json:"SonIsEmriVeren"`
ModelAdi string `json:"sAdi"`
Kodu string `json:"sKodu"`
SKullaniciAdi string `json:"sKullaniciAdi"`
SKullaniciGunc string `json:"sKullaniciAdiGunc"`
MMiktarG float64 `json:"lMMiktar_G"`
MModelKodu string `json:"sMModelKodu"`
}
type ProductionHasCostProductRow struct {
UretimSekli string `json:"UretimSekli"`
NOnMLNo string `json:"nOnMLNo"`
UrunKodu string `json:"UrunKodu"`
UrunAdi string `json:"UrunAdi"`
Tarihi string `json:"Tarihi"`
DteKayitTarihi string `json:"dteKayitTarihi"`
SKullaniciAdi string `json:"sKullaniciAdi"`
LTutarTL float64 `json:"lTutarTL"`
LTutarUSD float64 `json:"lTutarUSD"`
LTutarEURO float64 `json:"lTutarEURO"`
DteGuncellemeTarihi string `json:"dteGuncellemeTarihi"`
SGuncellemeKullaniciAdi string `json:"sGuncellemeKullaniciAdi"`
NUrtReceteID string `json:"nUrtReceteID"`
SAciklama string `json:"sAciklama"`
SonSiparisTarihi string `json:"SonSiparisTarihi"`
MaliyetDurumu string `json:"MaliyetDurumu"`
}
type ProductionHasCostHistoryRow struct {
NOnMLNo string `json:"nOnMLNo"`
UrunKodu string `json:"UrunKodu"`
UrunAdi string `json:"UrunAdi"`
Tarihi string `json:"Tarihi"`
SKullaniciAdi string `json:"sKullaniciAdi"`
LTutarUSD float64 `json:"lTutarUSD"`
LTutarTL float64 `json:"lTutarTL"`
LTutarEURO float64 `json:"lTutarEURO"`
LTutarGBP float64 `json:"lTutarGBP"`
SDovizCinsi string `json:"sDovizCinsi"`
LTutarDoviz float64 `json:"lTutarDoviz"`
DteGuncellemeTarihi string `json:"dteGuncellemeTarihi"`
SGuncellemeKullaniciAdi string `json:"sGuncellemeKullaniciAdi"`
NUrtReceteID string `json:"nUrtReceteID"`
SAciklama string `json:"sAciklama"`
}
type ProductionType struct {
ID string `json:"id"`
Aciklama string `json:"aciklama"`
}
type ProductionHasCostDetailGroupItem struct {
NOnMLNo string `json:"nOnMLNo"`
NOnMLDetNo string `json:"nOnMLDetNo"`
NHammaddeTuruNo string `json:"nHammaddeTuruNo"`
SKodu string `json:"sKodu"`
SAciklama string `json:"sAciklama"`
SRenk string `json:"sRenk"`
SBeden string `json:"sBeden"`
SAciklama2 string `json:"sAciklama2"`
LMiktar float64 `json:"lMiktar"`
LFiyat float64 `json:"lFiyat"`
LTutar float64 `json:"lTutar"`
SFiyatTipi string `json:"sFiyatTipi"`
SDovizCinsi string `json:"sDovizCinsi"`
LDovizKuru float64 `json:"lDovizKuru"`
LDovizFiyati float64 `json:"lDovizFiyati"`
FiyatGirilen *float64 `json:"fiyat_girilen"`
FiyatDoviz string `json:"fiyat_doviz"`
MaliyeteDahil bool `json:"maliyete_dahil"`
CMPriceTypeID *int `json:"cm_price_type_id"`
USDTutar float64 `json:"usdTutar"`
EURTutar float64 `json:"eurTutar"`
GBPTutar float64 `json:"gbpTutar"`
SBirim string `json:"sBirim"`
SHammaddeTuruAdi string `json:"sHammaddeTuruAdi"`
SParcaAdi string `json:"sParcaAdi"`
}
type ProductionHasCostDetailGroup struct {
SAciklama3 string `json:"sAciklama3"`
TotalTutar float64 `json:"totalTutar"`
TotalUSDTutar float64 `json:"totalUSDTutar"`
Items []ProductionHasCostDetailGroupItem `json:"items"`
}
type ProductionHasCostDetailHeader struct {
UretimiYapanFirma string `json:"UretimiYapanFirma"`
SonIsEmriVeren string `json:"SonIsEmriVeren"`
NOnMLNo string `json:"nOnMLNo"`
UrunKodu string `json:"UrunKodu"`
UrunAdi string `json:"UrunAdi"`
UrunAnaGrubu string `json:"UrunAnaGrubu"`
UrunAltGrubu string `json:"UrunAltGrubu"`
UretimSekliID string `json:"UretimSekliID"`
UretimSekli string `json:"UretimSekli"`
DteKayitTarihi string `json:"dteKayitTarihi"`
SKullaniciAdi string `json:"sKullaniciAdi"`
LTutarTL float64 `json:"lTutarTL"`
LTutarUSD float64 `json:"lTutarUSD"`
LTutarEURO float64 `json:"lTutarEURO"`
LTutarGBP float64 `json:"lTutarGBP"`
SDovizCinsi string `json:"sDovizCinsi"`
LTutarDoviz float64 `json:"lTutarDoviz"`
DteGuncellemeTarihi string `json:"dteGuncellemeTarihi"`
SGuncellemeKullaniciAdi string `json:"sGuncellemeKullaniciAdi"`
NUrtReceteID string `json:"nUrtReceteID"`
}
type ProductionHasCostDetailExchangeRates struct {
RateDate string `json:"rateDate"`
TRYRate float64 `json:"tryRate"`
USDRate float64 `json:"usdRate"`
EURRate float64 `json:"eurRate"`
GBPRate float64 `json:"gbpRate"`
}
type ProductionHasCostDetailEditorOption struct {
Kind string `json:"kind"`
Value string `json:"value"`
Label string `json:"label"`
NStokID string `json:"nStokID"`
NHammaddeTuruNo string `json:"nHammaddeTuruNo"`
SHammaddeTuruAdi string `json:"sHammaddeTuruAdi"`
SAciklama3 string `json:"sAciklama3"`
SKodu string `json:"sKodu"`
SAciklama string `json:"sAciklama"`
SModel string `json:"sModel"`
SBirim string `json:"sBirim"`
ColorCode string `json:"colorCode"`
ColorDescription string `json:"colorDescription"`
SParcaAdi string `json:"sParcaAdi"`
}
type ProductionHasCostDetailPriceLookupItem struct {
RowKey string `json:"__rowKey"`
NOnMLNo string `json:"n_onml_no"`
NOnMLDetNo string `json:"n_onml_det_no"`
NHammaddeTuruNo string `json:"n_hammadde_turu_no"`
SKodu string `json:"s_kodu"`
SAciklama string `json:"s_aciklama"`
SRenk string `json:"s_renk"`
ColorCode string `json:"color_code"`
ColorDescription string `json:"color_description"`
ItemDim1Code string `json:"item_dim1_code"`
ItemDim1Description string `json:"item_dim1_description"`
SBirim string `json:"s_birim"`
LMiktar float64 `json:"l_miktar"`
FiyatGirilen float64 `json:"fiyat_girilen"`
FiyatDoviz string `json:"fiyat_doviz"`
MaliyeteDahil int `json:"maliyete_dahil"`
CMPriceTypeID *int `json:"cm_price_type_id"`
}
type ProductionHasCostDetailBulkPriceRequest struct {
NOnMLNo string `json:"n_onml_no"`
UrunKodu string `json:"urun_kodu"`
NUrtReceteID string `json:"n_urt_recete_id"`
MaliyetTarihi string `json:"maliyet_tarihi"`
Items []ProductionHasCostDetailPriceLookupItem `json:"items"`
}
type ProductionHasCostDetailBulkPriceRow struct {
RowKey string `json:"__rowKey"`
NOnMLDetNo string `json:"nOnMLDetNo"`
NHammaddeTuruNo string `json:"nHammaddeTuruNo"`
SKodu string `json:"sKodu"`
ColorCode string `json:"ColorCode"`
ColorDescription string `json:"ColorDescription"`
ItemDim1Code string `json:"ItemDim1Code"`
ItemDim1Description string `json:"ItemDim1Description"`
FiyatGirilen float64 `json:"fiyat_girilen"`
FiyatDoviz string `json:"fiyat_doviz"`
PriceType string `json:"priceType"`
Tarih string `json:"Tarih"`
FaturaKodu string `json:"FaturaKodu"`
MasrafKodu string `json:"MasrafKodu"`
MasrafDetay string `json:"MasrafDetay"`
}
type ProductionHasCostDetailPurchaseHistoryRow struct {
SourceType string `json:"sourceType"`
Tarih string `json:"Tarih"`
FaturaKodu string `json:"FaturaKodu"`
FirmaKodu string `json:"FirmaKodu"`
FirmaAciklama string `json:"FirmaAciklama"`
MasrafKodu string `json:"MasrafKodu"`
MasrafDetay string `json:"MasrafDetay"`
ColorCode string `json:"ColorCode"`
ColorDescription string `json:"ColorDescription"`
ItemDim1Code string `json:"ItemDim1Code"`
ItemDim1Description string `json:"ItemDim1Description"`
Miktar float64 `json:"Miktar"`
BIRIM string `json:"BIRIM"`
EvrakFiyat float64 `json:"EvrakFiyat"`
EvrakTutar float64 `json:"EvrakTutar"`
EvrakDoviz string `json:"EvrakDoviz"`
PriceType string `json:"priceType"`
}
type ProductionHasCostDetailRecipeHistoryRow struct {
SourceType string `json:"sourceType"`
DteIslemTarihi string `json:"dteIslemTarihi"`
NOnMLNo string `json:"nOnMLNo"`
FirmaKodu string `json:"FirmaKodu"`
FirmaAciklama string `json:"FirmaAciklama"`
SKodu string `json:"sKodu"`
SAciklama string `json:"sAciklama"`
SRenk string `json:"sRenk"`
LMiktar float64 `json:"lMiktar"`
SBirim string `json:"sBirim"`
LDovizFiyati float64 `json:"lDovizFiyati"`
LDovizTutari float64 `json:"lDovizTutari"`
USD string `json:"USD"`
PriceType string `json:"priceType"`
DUMMY string `json:"DUMMY"`
}
type ProductionHasCostDetailLineHistoryResponse struct {
PurchaseRows []ProductionHasCostDetailPurchaseHistoryRow `json:"purchaseRows"`
RecipeRows []ProductionHasCostDetailRecipeHistoryRow `json:"recipeRows"`
}
type ProductionProductCostingMTBolumMappingRow struct {
ID int `json:"id"`
UrunAnaGrubu string `json:"urunAnaGrubu"`
UrunAltGrubu string `json:"urunAltGrubu"`
NUrtMTBolumID int `json:"nUrtMTBolumID"`
MTBolumAdi string `json:"mtBolumAdi"`
BAktif bool `json:"bAktif"`
DteIslem string `json:"dteIslemTarihi"`
SKullaniciAdi string `json:"sKullaniciAdi"`
}
type ProductionProductCostingMTBolumMappingUpsertRequest struct {
UrunAnaGrubu string `json:"urunAnaGrubu"`
UrunAltGrubu string `json:"urunAltGrubu"`
NUrtMTBolumID int `json:"nUrtMTBolumID"`
BAktif bool `json:"bAktif"`
}
// NEW: Maliyet Parca Eslestirme (Ana/Alt Grup + MTBolum + cok secmeli HammaddeTurleri)
type ProductionProductCostingParcaMappingRow struct {
ID int `json:"id"`
UrunIlkGrubu string `json:"urunIlkGrubu"`
UrunAnaGrubu string `json:"urunAnaGrubu"`
UrunAltGrubu string `json:"urunAltGrubu"`
NUrtMTBolumID int `json:"nUrtMTBolumID"`
ParcaBolumAdi string `json:"parcaBolumAdi"`
NHammaddeTurleri []string `json:"nHammaddeTurleri"`
BAktif bool `json:"bAktif"`
DteIslem string `json:"dteIslemTarihi"`
SKullaniciAdi string `json:"sKullaniciAdi"`
}
type ProductionProductCostingParcaMappingUpsertRequest struct {
UrunIlkGrubu string `json:"urunIlkGrubu"`
UrunAnaGrubu string `json:"urunAnaGrubu"`
UrunAltGrubu string `json:"urunAltGrubu"`
NUrtMTBolumID int `json:"nUrtMTBolumID"`
NHammaddeTurleri []int `json:"nHammaddeTurleri"`
BAktif bool `json:"bAktif"`
}
type ProductionProductCostingLookupOption struct {
Value string `json:"value"`
Label string `json:"label"`
}
type ProductionProductCostingAnaAltComboRow struct {
UrunIlkGrubu string `json:"urunIlkGrubu"`
UrunAnaGrubu string `json:"urunAnaGrubu"`
UrunAltGrubu string `json:"urunAltGrubu"`
}

View File

@@ -121,7 +121,14 @@ LEFT JOIN (
-- Paketlenen (OrderLine IsClosed=1) belge PB toplam
SUM(
CASE
WHEN ISNULL(l.IsClosed,0) = 1
WHEN (
ISNULL(l.IsClosed,0) = 1
OR EXISTS (
SELECT 1
FROM dbo.trInvoiceLine il WITH (NOLOCK)
WHERE il.OrderLineID = l.OrderLineID
)
)
AND c.CurrencyCode = h.DocCurrencyCode
THEN c.NetAmount
ELSE 0
@@ -131,7 +138,14 @@ LEFT JOIN (
-- Paketlenen TRY toplam
SUM(
CASE
WHEN ISNULL(l.IsClosed,0) = 1
WHEN (
ISNULL(l.IsClosed,0) = 1
OR EXISTS (
SELECT 1
FROM dbo.trInvoiceLine il WITH (NOLOCK)
WHERE il.OrderLineID = l.OrderLineID
)
)
AND c.CurrencyCode = 'TRY'
THEN c.NetAmount
ELSE 0

View File

@@ -216,7 +216,16 @@ SELECT
L.DeliveryDate,
L.PlannedDateOfLading,
L.LineDescription,
L.IsClosed,
CASE
WHEN ISNULL(L.IsClosed, 0) = 1
OR EXISTS (
SELECT 1
FROM BAGGI_V3.dbo.trInvoiceLine il WITH (NOLOCK)
WHERE il.OrderLineID = L.OrderLineID
)
THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS IsClosed,
L.CreatedUserName,
L.CreatedDate,
L.LastUpdatedUserName,

View File

@@ -143,15 +143,29 @@ JOIN (
) AS TotalTRY,
SUM(
CASE
-- "Paketlenen" = satir kapaliysa VEYA satir irsaliyeye/faturaya baglandiysa.
-- Not: IsClosed her zaman guncellenmiyor; trInvoiceLine.OrderLineID iliskiyi yakalar.
WHEN ISNULL(l.IsClosed,0) = 1
OR EXISTS (
SELECT 1
FROM dbo.trInvoiceLine il WITH (NOLOCK)
WHERE il.OrderLineID = l.OrderLineID
)
THEN ISNULL(c.NetAmount,0)
ELSE 0
END
) AS PackedAmount,
SUM(
CASE
WHEN ISNULL(l.IsClosed,0) = 1
AND ISNULL(c.CurrencyCode,'') = 'TRY'
WHEN (
ISNULL(l.IsClosed,0) = 1
OR EXISTS (
SELECT 1
FROM dbo.trInvoiceLine il WITH (NOLOCK)
WHERE il.OrderLineID = l.OrderLineID
)
)
AND ISNULL(c.CurrencyCode,'') = 'TRY'
THEN ISNULL(c.NetAmount,0)
ELSE 0
END

View File

@@ -0,0 +1,1702 @@
package queries
import (
"bssapp-backend/utils"
"context"
"database/sql"
"fmt"
"strconv"
"strings"
"unicode"
)
func GetProductAnaAltGrupByUrunKodu(ctx context.Context, mssqlDB *sql.DB, urunKodu string) (urunAnaGrubu string, urunAltGrubu string, err error) {
urunKodu = strings.TrimSpace(urunKodu)
if mssqlDB == nil || urunKodu == "" {
return "", "", nil
}
// Nebim V3: ProductFilterWithDescription exposes ProductAtt01Desc (ana grup) and ProductAtt02Desc (alt grup).
sqlText := `
SELECT TOP 1
ISNULL(ProductAtt01Desc, '') AS UrunAnaGrubu,
ISNULL(ProductAtt02Desc, '') AS UrunAltGrubu
FROM ProductFilterWithDescription('TR')
WHERE IsBlocked = 0
AND LTRIM(RTRIM(ProductCode)) = @p1
ORDER BY ProductCode;
`
row := mssqlDB.QueryRowContext(ctx, sqlText, urunKodu)
if err := row.Scan(&urunAnaGrubu, &urunAltGrubu); err != nil {
if err == sql.ErrNoRows {
return "", "", nil
}
return "", "", err
}
return urunAnaGrubu, urunAltGrubu, nil
}
func GetProductionProductCostingAnaGrupOptions(ctx context.Context, mssqlDB *sql.DB, search string, limit int) (*sql.Rows, error) {
search = strings.TrimSpace(search)
if limit <= 0 {
limit = 50
}
searchLike := "%" + search + "%"
sqlText := `
SELECT TOP (@p2)
ISNULL(NULLIF(LTRIM(RTRIM(P.ProductAtt01Desc)), ''), '') AS UrunAnaGrubu
FROM ProductFilterWithDescription('TR') AS P
WHERE P.IsBlocked = 0
AND NULLIF(LTRIM(RTRIM(P.ProductAtt01Desc)), '') IS NOT NULL
AND (@p1 = '' OR P.ProductAtt01Desc LIKE @p3)
GROUP BY P.ProductAtt01Desc
ORDER BY P.ProductAtt01Desc
`
return mssqlDB.QueryContext(ctx, sqlText, search, limit, searchLike)
}
func GetProductionProductCostingAltGrupOptions(ctx context.Context, mssqlDB *sql.DB, urunAnaGrubu string, search string, limit int) (*sql.Rows, error) {
urunAnaGrubu = strings.TrimSpace(urunAnaGrubu)
search = strings.TrimSpace(search)
if limit <= 0 {
limit = 50
}
searchLike := "%" + search + "%"
sqlText := `
SELECT TOP (@p3)
ISNULL(NULLIF(LTRIM(RTRIM(P.ProductAtt02Desc)), ''), '') AS UrunAltGrubu
FROM ProductFilterWithDescription('TR') AS P
WHERE P.IsBlocked = 0
AND NULLIF(LTRIM(RTRIM(P.ProductAtt02Desc)), '') IS NOT NULL
AND (@p1 = '' OR LTRIM(RTRIM(P.ProductAtt01Desc)) = @p1)
AND (@p2 = '' OR P.ProductAtt02Desc LIKE @p4)
GROUP BY P.ProductAtt02Desc
ORDER BY P.ProductAtt02Desc
`
return mssqlDB.QueryContext(ctx, sqlText, urunAnaGrubu, search, limit, searchLike)
}
func GetProductionProductCostingAnaAltComboRows(ctx context.Context, mssqlDB *sql.DB, search string, limit int) (*sql.Rows, error) {
search = strings.TrimSpace(search)
if limit <= 0 {
limit = 500
}
if limit > 5000 {
limit = 5000
}
// For very short searches, avoid leading-wildcard LIKE which can be extremely expensive on MSSQL side.
// Example: "ce" should match "CEKET%" cheaply vs "%ce%" scanning everything.
searchLike := "%" + search + "%"
if len([]rune(search)) > 0 && len([]rune(search)) < 3 {
searchLike = search + "%"
}
sqlText := `
SELECT TOP (@p2)
ISNULL(NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt42Desc))), ''), '') AS UrunIlkGrubu,
ISNULL(NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt01Desc))), ''), '') AS UrunAnaGrubu,
ISNULL(NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt02Desc))), ''), '') AS UrunAltGrubu
FROM ProductFilterWithDescription('TR') AS P
WHERE P.IsBlocked = 0
AND NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt42Desc))), '') IS NOT NULL
AND NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt01Desc))), '') IS NOT NULL
AND NULLIF(LTRIM(RTRIM(CONVERT(NVARCHAR(200), P.ProductAtt02Desc))), '') IS NOT NULL
AND (
@p1 = ''
OR CONVERT(NVARCHAR(200), P.ProductAtt42Desc) LIKE @p3
OR CONVERT(NVARCHAR(200), P.ProductAtt01Desc) LIKE @p3
OR CONVERT(NVARCHAR(200), P.ProductAtt02Desc) LIKE @p3
)
GROUP BY
CONVERT(NVARCHAR(200), P.ProductAtt42Desc),
CONVERT(NVARCHAR(200), P.ProductAtt01Desc),
CONVERT(NVARCHAR(200), P.ProductAtt02Desc)
ORDER BY
CONVERT(NVARCHAR(200), P.ProductAtt42Desc),
CONVERT(NVARCHAR(200), P.ProductAtt02Desc),
CONVERT(NVARCHAR(200), P.ProductAtt01Desc)
`
return mssqlDB.QueryContext(ctx, sqlText, search, limit, searchLike)
}
func GetProductionProductCostingMTBolumOptions(ctx context.Context, uretimDB *sql.DB, search string, limit int) (*sql.Rows, error) {
search = strings.TrimSpace(search)
if limit <= 0 {
limit = 50
}
searchLike := "%" + search + "%"
sqlText := `
SELECT TOP (@p2)
ISNULL(B.nUrtMTBolumID, 0) AS nUrtMTBolumID,
ISNULL(B.sAdi, '') AS sAdi
FROM dbo.spUrtMTBolum B WITH (NOLOCK)
WHERE ISNULL(B.bAktif, 0) = 1
AND (@p1 = '' OR ISNULL(B.sAdi, '') LIKE @p3 OR CONVERT(VARCHAR(32), ISNULL(B.nUrtMTBolumID, 0)) LIKE @p3)
ORDER BY B.nUrtMTBolumID
`
return uretimDB.QueryContext(ctx, sqlText, search, limit, searchLike)
}
// ============================================================
// Maliyet Parca Eslestirme (URETIM DB)
// ============================================================
func ListProductionProductCostingParcaMappings(ctx context.Context, uretimDB *sql.DB, urunIlkGrubu string, urunAnaGrubu string, urunAltGrubu string, nUrtMTBolumID int, onlyActive *bool) (*sql.Rows, error) {
urunIlkGrubu = strings.TrimSpace(urunIlkGrubu)
urunAnaGrubu = strings.TrimSpace(urunAnaGrubu)
urunAltGrubu = strings.TrimSpace(urunAltGrubu)
sqlText := `
SELECT
M.id,
ISNULL(M.UrunIlkGrubu, '') AS UrunIlkGrubu,
ISNULL(M.UrunAnaGrubu, '') AS UrunAnaGrubu,
ISNULL(M.UrunAltGrubu, '') AS UrunAltGrubu,
ISNULL(M.nUrtMTBolumID, 0) AS nUrtMTBolumID,
ISNULL(B.sAdi, '') AS MTBolumAdi,
ISNULL(H.HammaddeTurleri, '') AS HammaddeTurleri,
CAST(CASE WHEN ISNULL(M.bAktif, 0) = 1 THEN 1 ELSE 0 END AS bit) AS bAktif,
CONVERT(VARCHAR(16), M.dteIslemTarihi, 120) AS dteIslemTarihi,
ISNULL(M.sKullaniciAdi, '') AS sKullaniciAdi
FROM dbo.mk_MaliyetParcaEslestirme M WITH (NOLOCK)
LEFT JOIN dbo.spUrtMTBolum B WITH (NOLOCK)
ON B.nUrtMTBolumID = M.nUrtMTBolumID
OUTER APPLY (
SELECT
STUFF((
SELECT ',' + LTRIM(RTRIM(CONVERT(VARCHAR(32), X.nHammaddeTuruNo)))
FROM dbo.mk_MaliyetParcaEslestirme_HammaddeTuru X WITH (NOLOCK)
WHERE X.mapping_id = M.id
ORDER BY X.nHammaddeTuruNo
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, '') AS HammaddeTurleri
) H
WHERE (@p1 = '' OR LTRIM(RTRIM(M.UrunIlkGrubu)) = @p1)
AND (@p2 = '' OR LTRIM(RTRIM(M.UrunAnaGrubu)) = @p2)
AND (@p3 = '' OR LTRIM(RTRIM(M.UrunAltGrubu)) = @p3)
AND (@p4 <= 0 OR M.nUrtMTBolumID = @p4)
AND (@p5 IS NULL OR ISNULL(M.bAktif, 0) = @p5)
ORDER BY M.UrunAltGrubu, M.UrunAnaGrubu, M.nUrtMTBolumID
`
var activeParam any = nil
if onlyActive != nil {
if *onlyActive {
activeParam = 1
} else {
activeParam = 0
}
}
return uretimDB.QueryContext(ctx, sqlText, urunIlkGrubu, urunAnaGrubu, urunAltGrubu, nUrtMTBolumID, activeParam)
}
func UpsertProductionProductCostingParcaMapping(ctx context.Context, uretimDB *sql.DB, urunIlkGrubu string, urunAnaGrubu string, urunAltGrubu string, nUrtMTBolumID int, nHammaddeTurleri []int, bAktif bool, user string) (mappingID int, err error) {
urunIlkGrubu = strings.TrimSpace(urunIlkGrubu)
urunAnaGrubu = strings.TrimSpace(urunAnaGrubu)
urunAltGrubu = strings.TrimSpace(urunAltGrubu)
user = strings.TrimSpace(user)
activeVal := 0
if bAktif {
activeVal = 1
}
tx, err := uretimDB.BeginTx(ctx, nil)
if err != nil {
return 0, err
}
defer func() {
if err != nil {
_ = tx.Rollback()
}
}()
// 1) Upsert header row and get mapping id
sqlText := `
DECLARE @id INT;
SELECT TOP 1 @id = id
FROM dbo.mk_MaliyetParcaEslestirme WITH (UPDLOCK, HOLDLOCK)
WHERE LTRIM(RTRIM(UrunIlkGrubu)) = @p1
AND LTRIM(RTRIM(UrunAnaGrubu)) = @p2
AND LTRIM(RTRIM(UrunAltGrubu)) = @p3
AND nUrtMTBolumID = @p4;
IF @id IS NULL
BEGIN
INSERT INTO dbo.mk_MaliyetParcaEslestirme
(UrunIlkGrubu, UrunAnaGrubu, UrunAltGrubu, nUrtMTBolumID, bAktif, sKullaniciAdi, dteIslemTarihi)
VALUES
(@p1, @p2, @p3, @p4, @p5, NULLIF(@p6, ''), GETDATE());
SET @id = SCOPE_IDENTITY();
END
ELSE
BEGIN
UPDATE dbo.mk_MaliyetParcaEslestirme
SET bAktif = @p5,
sKullaniciAdiDeg = NULLIF(@p6, ''),
dteIslemTarihiDeg = GETDATE()
WHERE id = @id;
END
SELECT @id;
`
if err = tx.QueryRowContext(ctx, sqlText, urunIlkGrubu, urunAnaGrubu, urunAltGrubu, nUrtMTBolumID, activeVal, user).Scan(&mappingID); err != nil {
return 0, err
}
// 2) Replace child rows
if _, err = tx.ExecContext(ctx, `DELETE FROM dbo.mk_MaliyetParcaEslestirme_HammaddeTuru WHERE mapping_id = @p1;`, mappingID); err != nil {
return 0, err
}
insertChild := `INSERT INTO dbo.mk_MaliyetParcaEslestirme_HammaddeTuru (mapping_id, nHammaddeTuruNo) VALUES (@p1, @p2);`
seen := make(map[int]bool, len(nHammaddeTurleri))
for _, n := range nHammaddeTurleri {
if n <= 0 {
continue
}
if seen[n] {
continue
}
seen[n] = true
if _, err = tx.ExecContext(ctx, insertChild, mappingID, n); err != nil {
return 0, err
}
}
if err = tx.Commit(); err != nil {
return 0, err
}
return mappingID, nil
}
func SetProductionProductCostingParcaMappingActive(ctx context.Context, uretimDB *sql.DB, id int, bAktif bool, user string) error {
user = strings.TrimSpace(user)
activeVal := 0
if bAktif {
activeVal = 1
}
sqlText := `
UPDATE dbo.mk_MaliyetParcaEslestirme
SET bAktif = @p2,
sKullaniciAdiDeg = NULLIF(@p3, ''),
dteIslemTarihiDeg = GETDATE()
WHERE id = @p1;
`
_, err := uretimDB.ExecContext(ctx, sqlText, id, activeVal, user)
return err
}
func DeleteProductionProductCostingParcaMapping(ctx context.Context, uretimDB *sql.DB, id int) error {
tx, err := uretimDB.BeginTx(ctx, nil)
if err != nil {
return err
}
defer func() {
if err != nil {
_ = tx.Rollback()
}
}()
if _, err = tx.ExecContext(ctx, `DELETE FROM dbo.mk_MaliyetParcaEslestirme_HammaddeTuru WHERE mapping_id = @p1;`, id); err != nil {
return err
}
if _, err = tx.ExecContext(ctx, `DELETE FROM dbo.mk_MaliyetParcaEslestirme WHERE id = @p1;`, id); err != nil {
return err
}
return tx.Commit()
}
func GetProductionNoCostProducts(
ctx context.Context,
uretimDB *sql.DB,
fromDate string,
search string,
) (*sql.Rows, error) {
fromDate = strings.TrimSpace(fromDate)
if fromDate == "" {
fromDate = "2025-06-01"
}
search = strings.TrimSpace(search)
sqlText := `
SELECT
CASE
WHEN LEFT(LTRIM(RTRIM(R.sMModelKodu)), 1) IN ('N','X','S','O','I','K')
THEN N'BAGGI URUN TARAFINDAN URETIME VERILEN'
WHEN LEFT(LTRIM(RTRIM(R.sMModelKodu)), 1) IN ('P','F','M')
THEN N'FASON ICIN URETILEN'
ELSE N'Tanimsiz'
END AS UretimSekli,
RTRIM(CONVERT(VARCHAR(32), ISNULL(SonIsEmri.nUrtSiparisNo, 0))) AS nUrtSiparisNo,
CONVERT(VARCHAR(10), SonIsEmri.dteIslemTarihi, 23) AS dteIslemTarihi,
ISNULL(SonIsEmri.FirmaKodu, '') AS FirmaKodu,
ISNULL(SonIsEmri.FirmaAdi, '') AS FirmaAdi,
ISNULL(SonIsEmri.sVeren, '') AS SonIsEmriVeren,
ISNULL(SonIsEmri.lMMiktar_G, 0) AS lMMiktar_G,
LTRIM(RTRIM(R.sMModelKodu)) AS sMModelKodu,
ISNULL(R.sKodu, '') AS sKodu,
ISNULL(R.sAdi, '') AS sAdi,
ISNULL(R.sKullaniciAdi, '') AS sKullaniciAdi,
ISNULL(R.sKullaniciAdiGunc, '') AS sKullaniciAdiGunc
FROM dbo.spUrtRecete R
OUTER APPLY (
SELECT TOP 1
SD.nUrtSiparisID,
SM.nUrtSiparisNo,
SD.dteIslemTarihi,
SD.lMMiktar_G,
SM.sVeren,
F.nFirmaID,
F.sKodu AS FirmaKodu,
F.sAciklama AS FirmaAdi
FROM dbo.spUrtSiparisDet SD
INNER JOIN dbo.spUrtSiparis SM
ON SM.nUrtSiparisID = SD.nUrtSiparisID
LEFT JOIN dbo.tbFirma F
ON F.nFirmaID = SM.nFirmaID
WHERE SD.nUrtReceteID = R.nUrtReceteID
ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC
) SonIsEmri
WHERE LTRIM(RTRIM(R.sMModelKodu)) <> ''
AND LEN(LTRIM(RTRIM(R.sMModelKodu))) = 13
AND R.dteIslemTarihi > @p1
AND (
@p2 = ''
OR LTRIM(RTRIM(R.sMModelKodu)) LIKE '%' + @p2 + '%'
OR ISNULL(SonIsEmri.FirmaKodu, '') LIKE '%' + @p2 + '%'
OR ISNULL(SonIsEmri.FirmaAdi, '') LIKE '%' + @p2 + '%'
OR ISNULL(SonIsEmri.sVeren, '') LIKE '%' + @p2 + '%'
)
AND NOT EXISTS (
SELECT 1
FROM dbo.spUrtOnMLMas M
WHERE LTRIM(RTRIM(M.UrunKodu)) = LTRIM(RTRIM(R.sMModelKodu))
)
ORDER BY SonIsEmri.dteIslemTarihi DESC, LTRIM(RTRIM(R.sMModelKodu)) ASC
`
return uretimDB.QueryContext(ctx, sqlText, fromDate, search)
}
func GetProductionHasCostProducts(
ctx context.Context,
uretimDB *sql.DB,
search string,
offset int,
limit int,
) (*sql.Rows, error) {
search = strings.TrimSpace(search)
sqlText := `
WITH SonOnMaliyet AS (
SELECT
M.*,
ROW_NUMBER() OVER (
PARTITION BY LTRIM(RTRIM(M.UrunKodu))
ORDER BY
M.Tarihi DESC,
M.dteGuncellemeTarihi DESC,
M.nOnMLNo DESC
) AS rn
FROM dbo.spUrtOnMLMas M
WHERE LTRIM(RTRIM(M.UrunKodu)) <> ''
),
SonSiparis AS (
SELECT
LTRIM(RTRIM(sMModelKodu)) AS UrunKodu,
MAX(dteIslemTarihi) AS SonSiparisTarihi
FROM dbo.spUrtSiparisDet
GROUP BY LTRIM(RTRIM(sMModelKodu))
)
SELECT
CASE
WHEN LEFT(LTRIM(RTRIM(OM.UrunKodu)), 1) IN ('N','X','S','O','I','K')
THEN N'BAGGI URUN TARAFINDAN URETIME VERILEN'
WHEN LEFT(LTRIM(RTRIM(OM.UrunKodu)), 1) IN ('P','F','M')
THEN N'FASON ICIN URETILEN'
ELSE N'Tanimsiz'
END AS UretimSekli,
RTRIM(CONVERT(VARCHAR(32), ISNULL(OM.nOnMLNo, 0))) AS nOnMLNo,
LTRIM(RTRIM(ISNULL(OM.UrunKodu, ''))) AS UrunKodu,
ISNULL(OM.UrunAdi, '') AS UrunAdi,
CONVERT(VARCHAR(10), OM.Tarihi, 23) AS Tarihi,
CONVERT(VARCHAR(10), OM.dteKayitTarihi, 23) AS dteKayitTarihi,
ISNULL(OM.sKullaniciAdi, '') AS sKullaniciAdi,
ISNULL(OM.lTutarTL, 0) AS lTutarTL,
ISNULL(OM.lTutarUSD, 0) AS lTutarUSD,
ISNULL(OM.lTutarEURO, 0) AS lTutarEURO,
CONVERT(VARCHAR(10), OM.dteGuncellemeTarihi, 23) AS dteGuncellemeTarihi,
ISNULL(OM.sGuncellemeKullaniciAdi, '') AS sGuncellemeKullaniciAdi,
RTRIM(CONVERT(VARCHAR(32), ISNULL(OM.nUrtReceteID, 0))) AS nUrtReceteID,
ISNULL(OM.sAciklama, '') AS sAciklama,
ISNULL(CONVERT(VARCHAR(10), SS.SonSiparisTarihi, 23), '') AS SonSiparisTarihi,
CASE
WHEN ISNULL(OM.lTutarUSD, 0) = 0 THEN N'GUNCELLEME GEREKIYOR'
WHEN SS.SonSiparisTarihi IS NULL THEN N'SIPARIS YOK'
WHEN SS.SonSiparisTarihi > OM.Tarihi THEN N'GUNCELLEME GEREKIYOR'
ELSE N'GUNCEL'
END AS MaliyetDurumu
FROM SonOnMaliyet OM
LEFT JOIN SonSiparis SS
ON SS.UrunKodu = LTRIM(RTRIM(OM.UrunKodu))
WHERE OM.rn = 1
AND (
@p1 = ''
OR RTRIM(CONVERT(VARCHAR(32), ISNULL(OM.nOnMLNo, 0))) LIKE '%' + @p1 + '%'
OR LTRIM(RTRIM(OM.UrunKodu)) LIKE '%' + @p1 + '%'
OR ISNULL(OM.UrunAdi, '') LIKE '%' + @p1 + '%'
OR ISNULL(OM.sAciklama, '') LIKE '%' + @p1 + '%'
)
ORDER BY
SS.SonSiparisTarihi DESC,
OM.nOnMLNo DESC
OFFSET @p2 ROWS
FETCH NEXT @p3 ROWS ONLY
`
return uretimDB.QueryContext(ctx, sqlText, search, offset, limit)
}
func GetProductionHasCostHistoryByProductCode(
ctx context.Context,
uretimDB *sql.DB,
productCode string,
) (*sql.Rows, error) {
productCode = strings.TrimSpace(productCode)
sqlText := `
SELECT
RTRIM(CONVERT(VARCHAR(32), ISNULL(M.nOnMLNo, 0))) AS nOnMLNo,
LTRIM(RTRIM(ISNULL(M.UrunKodu, ''))) AS UrunKodu,
ISNULL(M.UrunAdi, '') AS UrunAdi,
CONVERT(VARCHAR(16), M.Tarihi, 120) AS Tarihi,
ISNULL(M.sKullaniciAdi, '') AS sKullaniciAdi,
ISNULL(M.lTutarUSD, 0) AS lTutarUSD,
ISNULL(M.lTutarTL, 0) AS lTutarTL,
ISNULL(M.lTutarEURO, 0) AS lTutarEURO,
ISNULL(M.sDovizCinsi, '') AS sDovizCinsi,
ISNULL(M.lTutarDoviz, 0) AS lTutarDoviz,
CONVERT(VARCHAR(16), M.dteGuncellemeTarihi, 120) AS dteGuncellemeTarihi,
ISNULL(M.sGuncellemeKullaniciAdi, '') AS sGuncellemeKullaniciAdi,
RTRIM(CONVERT(VARCHAR(32), ISNULL(M.nUrtReceteID, 0))) AS nUrtReceteID,
ISNULL(M.sAciklama, '') AS sAciklama
FROM dbo.spUrtOnMLMas M
WHERE LTRIM(RTRIM(M.UrunKodu)) = @p1
ORDER BY
M.Tarihi DESC,
M.dteGuncellemeTarihi DESC,
M.nOnMLNo DESC
`
return uretimDB.QueryContext(ctx, sqlText, productCode)
}
func GetProductionHasCostDetailRowsByOnMLNo(
ctx context.Context,
uretimDB *sql.DB,
nOnMLNo int,
) (*sql.Rows, error) {
sqlText := `
SELECT
ISNULL(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), N'TANIMSIZ') AS sAciklama3,
SUM(ISNULL(D.lTutar, 0)) OVER (
PARTITION BY ISNULL(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), N'TANIMSIZ')
) AS GroupTotalTutar,
SUM(ISNULL(D.lMiktar, 0) * ISNULL(D.lDovizFiyati, 0)) OVER (
PARTITION BY ISNULL(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), N'TANIMSIZ')
) AS GroupTotalUSDTutar,
RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLNo, 0))) AS nOnMLNo,
RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLDetNo, 0))) AS nOnMLDetNo,
RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nHammaddeTuruNo, 0))) AS nHammaddeTuruNo,
ISNULL(D.sKodu, '') AS sKodu,
ISNULL(D.sAciklama, '') AS sAciklama,
ISNULL(D.sRenk, '') AS sRenk,
ISNULL(D.sBeden, '') AS sBeden,
ISNULL(D.sAciklama2, '') AS sAciklama2,
ISNULL(D.lMiktar, 0) AS lMiktar,
ISNULL(D.lFiyat, 0) AS lFiyat,
ISNULL(D.lTutar, 0) AS lTutar,
ISNULL(D.sFiyatTipi, '') AS sFiyatTipi,
ISNULL(D.sDovizCinsi, '') AS sDovizCinsi,
ISNULL(D.lDovizKuru, 0) AS lDovizKuru,
ISNULL(D.lDovizFiyati, 0) AS lDovizFiyati,
D.fiyat_girilen AS fiyat_girilen,
D.fiyat_doviz AS fiyat_doviz,
CAST(CASE WHEN ISNULL(D.Maliyete_dahil, 0) = 1 THEN 1 ELSE 0 END AS bit) AS maliyete_dahil,
D.cm_price_type_id AS cm_price_type_id,
ISNULL(D.lMiktar, 0) * ISNULL(D.lDovizFiyati, 0) AS usdTutar,
0.0 AS eurTutar,
0.0 AS gbpTutar,
ISNULL(D.sBirim, '') AS sBirim,
ISNULL(T.sAciklama, '') AS sHammaddeTuruAdi,
ISNULL(B.sAdi, '') AS sParcaAdi
FROM dbo.spUrtOnMLMasDet D
LEFT JOIN dbo.spUrtOnMLHammaddeTuru T
ON T.nHammaddeTuruNo = D.nHammaddeTuruNo
LEFT JOIN dbo.spUrtMTBolum B
ON B.nUrtMTBolumID = D.nUrtMTBolumID
WHERE D.nOnMLNo = @p1
ORDER BY
GroupTotalTutar DESC,
sAciklama3 ASC,
ISNULL(D.lTutar, 0) DESC,
D.nOnMLDetNo ASC
`
return uretimDB.QueryContext(ctx, sqlText, nOnMLNo)
}
func GetProductionHasCostDetailHeaderByOnMLNo(
ctx context.Context,
uretimDB *sql.DB,
nOnMLNo int,
) (*sql.Row, error) {
sqlText := `
SELECT TOP 1
ISNULL(UF.UretimiYapanFirma, '') AS UretimiYapanFirma,
ISNULL(UF.SonIsEmriVeren, '') AS SonIsEmriVeren,
RTRIM(CONVERT(VARCHAR(32), ISNULL(M.nOnMLNo, 0))) AS nOnMLNo,
LTRIM(RTRIM(ISNULL(M.UrunKodu, ''))) AS UrunKodu,
ISNULL(M.UrunAdi, '') AS UrunAdi,
RTRIM(CONVERT(VARCHAR(32), ISNULL(M.uretim_sekli_id, 0))) AS uretim_sekli_id,
ISNULL(US.aciklama, '') AS uretim_sekli,
CONVERT(VARCHAR(16), M.dteKayitTarihi, 120) AS dteKayitTarihi,
ISNULL(M.sKullaniciAdi, '') AS sKullaniciAdi,
ISNULL(M.lTutarTL, 0) AS lTutarTL,
ISNULL(M.lTutarUSD, 0) AS lTutarUSD,
ISNULL(M.lTutarEURO, 0) AS lTutarEURO,
0.0 AS lTutarGBP,
ISNULL(M.sDovizCinsi, '') AS sDovizCinsi,
ISNULL(M.lTutarDoviz, 0) AS lTutarDoviz,
CONVERT(VARCHAR(16), M.dteGuncellemeTarihi, 120) AS dteGuncellemeTarihi,
ISNULL(M.sGuncellemeKullaniciAdi, '') AS sGuncellemeKullaniciAdi,
RTRIM(CONVERT(VARCHAR(32), ISNULL(M.nUrtReceteID, 0))) AS nUrtReceteID
FROM dbo.spUrtOnMLMas M
LEFT JOIN dbo.mk_uretim_sekli US
ON US.id = M.uretim_sekli_id
OUTER APPLY (
SELECT TOP 1
ISNULL(F.sAciklama, '') AS UretimiYapanFirma,
ISNULL(SM.sVeren, '') AS SonIsEmriVeren
FROM dbo.spUrtSiparisDet SD
INNER JOIN dbo.spUrtSiparis SM
ON SM.nUrtSiparisID = SD.nUrtSiparisID
LEFT JOIN dbo.tbFirma F
ON F.nFirmaID = SM.nFirmaID
WHERE LTRIM(RTRIM(SD.sMModelKodu)) = LTRIM(RTRIM(M.UrunKodu))
ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC
) UF
WHERE M.nOnMLNo = @p1
ORDER BY M.nOnMLNo DESC
`
return uretimDB.QueryRowContext(ctx, sqlText, nOnMLNo), nil
}
func GetProductionNoCostDetailHeaderByRecipeCode(
ctx context.Context,
uretimDB *sql.DB,
recipeCode string,
productCode string,
) (*sql.Row, error) {
recipeCode = strings.TrimSpace(recipeCode)
productCode = strings.TrimSpace(productCode)
utils.SlogFromContext(ctx).With(
"query", "production-product-costing.no-cost-detail-header",
"recete_kodu", recipeCode,
"urun_kodu", productCode,
).Info("query dispatch")
sqlText := `
WITH RecipeMatch AS (
SELECT TOP 1
R.nUrtReceteID,
LTRIM(RTRIM(ISNULL(R.sMModelKodu, ''))) AS UrunKodu,
ISNULL(R.sAdi, '') AS UrunAdi,
CONVERT(VARCHAR(16), R.dteIslemTarihi, 120) AS dteKayitTarihi,
ISNULL(R.sKullaniciAdi, '') AS sKullaniciAdi,
ISNULL(R.sKullaniciAdiGunc, '') AS sGuncellemeKullaniciAdi,
CASE
WHEN LEFT(LTRIM(RTRIM(R.sMModelKodu)), 1) IN ('N','X','S','O','I','K')
THEN N'BAGGI URUN TARAFINDAN URETIME VERILEN'
WHEN LEFT(LTRIM(RTRIM(R.sMModelKodu)), 1) IN ('P','F','M')
THEN N'FASON ICIN URETILEN'
ELSE N'Tanimsiz'
END AS UretimSekli
FROM dbo.spUrtRecete R
WHERE LTRIM(RTRIM(ISNULL(R.sKodu, ''))) = @p1
AND (@p2 = '' OR LTRIM(RTRIM(ISNULL(R.sMModelKodu, ''))) = @p2)
ORDER BY
R.dteIslemTarihi DESC,
R.nUrtReceteID DESC
)
SELECT TOP 1
ISNULL(SonIsEmri.FirmaAdi, '') AS UretimiYapanFirma,
ISNULL(SonIsEmri.SonIsEmriVeren, '') AS SonIsEmriVeren,
'' AS nOnMLNo,
RM.UrunKodu,
RM.UrunAdi,
'' AS UretimSekliID,
RM.UretimSekli,
ISNULL(SonIsEmri.dteIslemTarihi, RM.dteKayitTarihi) AS dteKayitTarihi,
RM.sKullaniciAdi,
0.0 AS lTutarTL,
0.0 AS lTutarUSD,
0.0 AS lTutarEURO,
0.0 AS lTutarGBP,
'USD' AS sDovizCinsi,
0.0 AS lTutarDoviz,
'' AS dteGuncellemeTarihi,
RM.sGuncellemeKullaniciAdi,
RTRIM(CONVERT(VARCHAR(32), ISNULL(RM.nUrtReceteID, 0))) AS nUrtReceteID
FROM RecipeMatch RM
OUTER APPLY (
SELECT TOP 1
ISNULL(F.sAciklama, '') AS FirmaAdi,
ISNULL(SM.sVeren, '') AS SonIsEmriVeren,
CONVERT(VARCHAR(16), SD.dteIslemTarihi, 120) AS dteIslemTarihi
FROM dbo.spUrtSiparisDet SD
INNER JOIN dbo.spUrtSiparis SM
ON SM.nUrtSiparisID = SD.nUrtSiparisID
LEFT JOIN dbo.tbFirma F
ON F.nFirmaID = SM.nFirmaID
WHERE SD.nUrtReceteID = RM.nUrtReceteID
ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC
) SonIsEmri
`
return uretimDB.QueryRowContext(ctx, sqlText, recipeCode, productCode), nil
}
func GetProductionNoCostDetailRowsByRecipeCode(
ctx context.Context,
uretimDB *sql.DB,
recipeCode string,
productCode string,
) (*sql.Rows, error) {
recipeCode = strings.TrimSpace(recipeCode)
productCode = strings.TrimSpace(productCode)
logger := utils.SlogFromContext(ctx).With(
"query", "production-product-costing.no-cost-detail-rows",
"recete_kodu", recipeCode,
"urun_kodu", productCode,
)
logger.Info("query dispatch")
sqlText := `
WITH RecipeMatch AS (
SELECT TOP 1
R.nUrtReceteID
FROM dbo.spUrtRecete R
WHERE LTRIM(RTRIM(ISNULL(R.sKodu, ''))) = @p1
AND (@p2 = '' OR LTRIM(RTRIM(ISNULL(R.sMModelKodu, ''))) = @p2)
ORDER BY
R.dteIslemTarihi DESC,
R.nUrtReceteID DESC
),
HammaddeTekil AS (
SELECT
ISNULL(NULLIF(LTRIM(RTRIM(HT.sAciklama3)), ''), ISNULL(NULLIF(LTRIM(RTRIM(HT.sAciklama)), ''), N'TANIMSIZ')) AS sAciklama3,
ISNULL(HT.nHammaddeTuruNo, 0) AS nHammaddeTuruNoSort,
RTRIM(CONVERT(VARCHAR(32), ISNULL(HT.nHammaddeTuruNo, 0))) AS nHammaddeTuruNo,
-- Match URETIM's sp_pUrtOnMaliyetRecetedenKop behavior: use model code + color code instead of variant stock code.
ISNULL(S.sModel, ISNULL(S.sKodu, '')) AS sKodu,
ISNULL(S.sAciklama, '') AS sAciklama,
ISNULL(S.sRenk, '') AS sRenk,
ISNULL(HT.sAciklama, '') AS sHammaddeTuruAdi,
ISNULL(S.sBirimCinsi1, '') AS sBirim,
ISNULL(RMik.lHMiktar, 0) AS lMiktar,
ROW_NUMBER() OVER (
PARTITION BY HT.nHammaddeTuruNo
ORDER BY ISNULL(S.sModel, ISNULL(S.sKodu, ''))
) AS rn,
ROW_NUMBER() OVER (
ORDER BY HT.nHammaddeTuruNo, ISNULL(S.sModel, ISNULL(S.sKodu, ''))
) AS rowNo
FROM RecipeMatch R
INNER JOIN dbo.spUrtRecMBolumMik RMik
ON RMik.nUrtReceteID = R.nUrtReceteID
LEFT JOIN dbo.tbStok S
ON S.nStokID = RMik.nHStokID
OUTER APPLY (
SELECT TOP 1
H.nHammaddeTuruNo,
H.sAciklama,
H.sAciklama3
FROM dbo.spUrtOnMLHammaddeTuru H
WHERE H.nUrtMBolumID = RMik.nUrtMBolumID
ORDER BY
CASE WHEN H.nUrtMTBolumID = RMik.nUrtMTBolumID THEN 0 ELSE 1 END,
H.nHammaddeTuruNo
) HT
WHERE HT.nHammaddeTuruNo IS NOT NULL
)
SELECT
HT.sAciklama3,
0.0 AS GroupTotalTutar,
0.0 AS GroupTotalUSDTutar,
'' AS nOnMLNo,
RTRIM(CONVERT(VARCHAR(32), ISNULL(HT.rowNo, 0))) AS nOnMLDetNo,
HT.nHammaddeTuruNo,
HT.sKodu,
HT.sAciklama,
HT.sRenk AS sRenk,
'' AS sBeden,
'' AS sAciklama2,
HT.lMiktar,
0.0 AS lFiyat,
0.0 AS lTutar,
'' AS sFiyatTipi,
'USD' AS sDovizCinsi,
0.0 AS lDovizKuru,
0.0 AS lDovizFiyati,
NULL AS fiyat_girilen,
'' AS fiyat_doviz,
CAST(1 AS bit) AS maliyete_dahil,
NULL AS cm_price_type_id,
0.0 AS usdTutar,
0.0 AS eurTutar,
0.0 AS gbpTutar,
HT.sBirim,
HT.sHammaddeTuruAdi,
HT.sHammaddeTuruAdi AS sParcaAdi
FROM HammaddeTekil HT
WHERE HT.rn = 1
ORDER BY
HT.nHammaddeTuruNoSort,
HT.sKodu
`
rows, err := uretimDB.QueryContext(ctx, sqlText, recipeCode, productCode)
if err != nil {
logger.Error("query error", "err", err)
return nil, err
}
return rows, nil
}
func GetProductionTypes(ctx context.Context, uretimDB *sql.DB) (*sql.Rows, error) {
sqlText := `SELECT id, aciklama FROM dbo.mk_uretim_sekli ORDER BY id`
return uretimDB.QueryContext(ctx, sqlText)
}
func GetProductionHasCostDetailHammaddeTypeOptions(
ctx context.Context,
uretimDB *sql.DB,
search string,
limit int,
) (*sql.Rows, error) {
search = strings.TrimSpace(search)
if limit <= 0 {
limit = 50
}
searchLike := "%" + search + "%"
sqlText := `
SELECT TOP (@p2)
RTRIM(CONVERT(VARCHAR(32), ISNULL(T.nHammaddeTuruNo, 0))) AS nHammaddeTuruNo,
ISNULL(T.sAciklama, '') AS sHammaddeTuruAdi,
ISNULL(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), N'TANIMSIZ') AS sAciklama3
FROM dbo.spUrtOnMLHammaddeTuru T
WHERE
ISNULL(T.bAktif, 0) = 1
AND (
@p1 = ''
OR RTRIM(CONVERT(VARCHAR(32), ISNULL(T.nHammaddeTuruNo, 0))) LIKE @p3
OR ISNULL(T.sAciklama, '') LIKE @p3
OR ISNULL(T.sAciklama3, '') LIKE @p3
)
ORDER BY
CASE
WHEN @p1 <> '' AND RTRIM(CONVERT(VARCHAR(32), ISNULL(T.nHammaddeTuruNo, 0))) = @p1 THEN 0
WHEN @p1 <> '' AND ISNULL(T.sAciklama, '') = @p1 THEN 1
ELSE 2
END,
T.nHammaddeTuruNo
`
return uretimDB.QueryContext(ctx, sqlText, search, limit, searchLike)
}
func buildSQLServerFullTextPrefixQuery(search string) string {
terms := strings.Fields(strings.TrimSpace(search))
parts := make([]string, 0, len(terms))
for _, term := range terms {
cleaned := strings.Map(func(r rune) rune {
if unicode.IsLetter(r) || unicode.IsDigit(r) {
return r
}
return -1
}, term)
if len([]rune(cleaned)) < 2 {
continue
}
parts = append(parts, fmt.Sprintf("\"%s*\"", cleaned))
}
return strings.Join(parts, " AND ")
}
func hasProductionHasCostDetailItemFullTextIndex(
ctx context.Context,
uretimDB *sql.DB,
) bool {
var exists int
err := uretimDB.QueryRowContext(ctx, `
SELECT CASE
WHEN EXISTS (
SELECT 1
FROM sys.fulltext_indexes fi
INNER JOIN sys.fulltext_index_columns fic
ON fic.object_id = fi.object_id
INNER JOIN sys.columns c
ON c.object_id = fic.object_id
AND c.column_id = fic.column_id
WHERE fi.object_id = OBJECT_ID('dbo.tbStok')
AND c.name = 'sAciklama'
) THEN 1 ELSE 0
END`).Scan(&exists)
return err == nil && exists == 1
}
func GetProductionHasCostDetailItemOptions(
ctx context.Context,
uretimDB *sql.DB,
search string,
limit int,
) (*sql.Rows, error) {
search = strings.TrimSpace(search)
if limit <= 0 {
limit = 50
}
if search == "" {
return uretimDB.QueryContext(ctx, `
SELECT TOP (0)
RTRIM(CONVERT(VARCHAR(32), ISNULL(S.nStokID, 0))) AS nStokID,
LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) AS sKodu,
LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sAciklama, '')))) AS sAciklama,
LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) AS sModel,
LTRIM(RTRIM(CONVERT(NVARCHAR(64), ISNULL(S.sBirimCinsi1, '')))) AS sBirim
FROM dbo.tbStok S`)
}
searchExact := search
searchPrefix := search + "%"
searchLike := "%" + search + "%"
searchLen := len([]rune(search))
numericStokID, numericErr := strconv.Atoi(search)
hasNumericStokID := numericErr == nil
fullTextSearch := buildSQLServerFullTextPrefixQuery(search)
useFullText := searchLen >= 3 && fullTextSearch != "" && hasProductionHasCostDetailItemFullTextIndex(ctx, uretimDB)
baseSelect := `
SELECT TOP (@p2)
RTRIM(CONVERT(VARCHAR(32), ISNULL(S.nStokID, 0))) AS nStokID,
LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) AS sKodu,
LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sAciklama, '')))) AS sAciklama,
LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) AS sModel,
LTRIM(RTRIM(CONVERT(NVARCHAR(64), ISNULL(S.sBirimCinsi1, '')))) AS sBirim
FROM dbo.tbStok S
WHERE
(ISNULL(S.IsBlocked, 0) = 0)
AND S.sModel LIKE '_.%%'
AND (
(@p5 = 1 AND S.nStokID = @p6)
OR S.sKodu = @p1
OR S.sKodu LIKE @p3
OR %s
)
ORDER BY
CASE
WHEN S.sKodu = @p1 THEN 0
WHEN (@p5 = 1 AND S.nStokID = @p6) THEN 1
WHEN S.sKodu LIKE @p3 THEN 2
ELSE 3
END,
S.sKodu
OPTION (RECOMPILE)
`
if useFullText {
sqlText := fmt.Sprintf(baseSelect, `CONTAINS(S.sAciklama, @p4)`)
return uretimDB.QueryContext(ctx, sqlText, searchExact, limit, searchPrefix, fullTextSearch, hasNumericStokID, numericStokID)
}
sqlText := fmt.Sprintf(baseSelect, `(@p4 >= 3 AND S.sAciklama LIKE @p7)`)
return uretimDB.QueryContext(ctx, sqlText, searchExact, limit, searchPrefix, searchLen, hasNumericStokID, numericStokID, searchLike)
}
func GetProductionHasCostDetailColorOptions(
ctx context.Context,
mssqlDB *sql.DB,
modelCode string,
search string,
limit int,
) (*sql.Rows, error) {
modelCode = strings.TrimSpace(modelCode)
search = strings.TrimSpace(search)
if limit <= 0 {
limit = 50
}
searchLike := "%" + search + "%"
sqlText := `
WITH ColorSource AS (
SELECT DISTINCT
LTRIM(RTRIM(CONVERT(NVARCHAR(64), ISNULL(T.sRenk, '')))) AS ColorCode
FROM dbo.tbStok T
WHERE ISNULL(T.IsBlocked, 0) = 0
AND LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(T.sModel, '')))) = @p1
AND LTRIM(RTRIM(CONVERT(NVARCHAR(64), ISNULL(T.sRenk, '')))) <> ''
)
SELECT TOP (@p2)
LTRIM(RTRIM(ISNULL(S.ColorCode, ''))) AS colorCode,
ISNULL(C.ColorDescription, '') AS colorDescription
FROM (
SELECT ColorCode
FROM ColorSource
) S
OUTER APPLY (
SELECT TOP 1 ColorDescription
FROM dbo.cdColorDesc CD
WHERE CD.LangCode = 'TR'
AND LTRIM(RTRIM(ISNULL(CD.ColorCode, ''))) = S.ColorCode
) C
WHERE @p1 <> ''
AND (
@p3 = ''
OR LTRIM(RTRIM(ISNULL(S.ColorCode, ''))) LIKE @p4
OR ISNULL(C.ColorDescription, '') LIKE @p4
)
ORDER BY
CASE
WHEN @p3 <> '' AND LTRIM(RTRIM(ISNULL(S.ColorCode, ''))) = @p3 THEN 0
WHEN @p3 <> '' AND ISNULL(C.ColorDescription, '') = @p3 THEN 1
ELSE 2
END,
LTRIM(RTRIM(ISNULL(S.ColorCode, '')))
`
return mssqlDB.QueryContext(ctx, sqlText, modelCode, limit, search, searchLike)
}
func GetProductionHasCostDetailExchangeRatesByDate(
ctx context.Context,
mssqlDB *sql.DB,
costDate string,
) (*sql.Row, error) {
costDate = strings.TrimSpace(costDate)
sqlText := `
DECLARE @targetDate date = ISNULL(CONVERT(date, NULLIF(@p1, ''), 23), CONVERT(date, GETDATE()))
SELECT
CONVERT(VARCHAR(10), @targetDate, 23) AS rateDate,
ISNULL((
SELECT TOP 1 Rate
FROM dbo.AllExchangeRates
WHERE CurrencyCode = 'USD'
AND RelationCurrencyCode = 'TRY'
AND ExchangeTypeCode = 6
AND Rate > 0
AND CONVERT(date, [Date]) <= @targetDate
ORDER BY
CASE WHEN CONVERT(date, [Date]) = @targetDate THEN 0 ELSE 1 END,
[Date] DESC
), 0) AS usdRate,
ISNULL((
SELECT TOP 1 Rate
FROM dbo.AllExchangeRates
WHERE CurrencyCode = 'EUR'
AND RelationCurrencyCode = 'TRY'
AND ExchangeTypeCode = 6
AND Rate > 0
AND CONVERT(date, [Date]) <= @targetDate
ORDER BY
CASE WHEN CONVERT(date, [Date]) = @targetDate THEN 0 ELSE 1 END,
[Date] DESC
), 0) AS eurRate,
ISNULL((
SELECT TOP 1 Rate
FROM dbo.AllExchangeRates
WHERE CurrencyCode = 'GBP'
AND RelationCurrencyCode = 'TRY'
AND ExchangeTypeCode = 6
AND Rate > 0
AND CONVERT(date, [Date]) <= @targetDate
ORDER BY
CASE WHEN CONVERT(date, [Date]) = @targetDate THEN 0 ELSE 1 END,
[Date] DESC
), 0) AS gbpRate
`
return mssqlDB.QueryRowContext(ctx, sqlText, costDate), nil
}
func GetProductionHasCostLatestPurchasePriceForItem(
ctx context.Context,
mssqlDB *sql.DB,
sKodu string,
colorCode string,
itemDim1Code string,
costDate string,
) (*sql.Row, error) {
sKodu = strings.TrimSpace(sKodu)
colorCode = strings.TrimSpace(colorCode)
itemDim1Code = strings.TrimSpace(itemDim1Code)
costDate = strings.TrimSpace(costDate)
sqlText := `
WITH BASE AS (
SELECT
A.InvoiceDate,
A.InvoiceNumber,
A.ProcessCode,
A.CurrAccTypeCode,
A.CurrAccCode,
A.ItemTypeCode,
A.ItemCode,
A.ColorCode,
A.ItemDim1Code,
A.Qty1,
A.Doc_Price,
A.Doc_Amount,
A.Doc_CurrencyCode
FROM AllInvoicesWithAttributes A
WHERE A.ProcessCode IN ('BP')
AND A.ATAtt01 IN (1, 2)
AND A.CompanyCode IN (1, 2, 5)
AND A.IsCompleted = 1
AND YEAR(A.InvoiceDate) >= 2022
AND LTRIM(RTRIM(A.ItemCode)) = @p1
AND (NULLIF(@p2, '') IS NULL OR CONVERT(date, A.InvoiceDate) < CONVERT(date, NULLIF(@p2, ''), 23))
)
SELECT TOP 1
'MAN' AS priceType,
CONVERT(VARCHAR(16), B.InvoiceDate, 120) AS Tarih,
ISNULL(B.InvoiceNumber, '') AS FaturaKodu,
LTRIM(RTRIM(ISNULL(B.ItemCode, ''))) AS MasrafKodu,
ISNULL(ID.ItemDescription, '') AS MasrafDetay,
ISNULL(B.ColorCode, '') AS ColorCode,
ISNULL(COL.ColorDescription, '') AS ColorDescription,
ISNULL(B.ItemDim1Code, '') AS ItemDim1Code,
ISNULL(DIM1.ItemDim1Description, '') AS ItemDim1Description,
ISNULL(B.Doc_Price, 0) AS EvrakFiyat,
ISNULL(B.Doc_CurrencyCode, '') AS EvrakDoviz
FROM BASE B
LEFT JOIN cdItem CI
ON CI.ItemTypeCode = B.ItemTypeCode
AND CI.ItemCode = B.ItemCode
OUTER APPLY (
SELECT TOP 1 ItemDescription
FROM cdItemDesc
WHERE ItemTypeCode = B.ItemTypeCode
AND ItemCode = B.ItemCode
AND LangCode = 'TR'
) ID
OUTER APPLY (
SELECT TOP 1 ItemDim1Description
FROM cdItemDim1Desc
WHERE ItemDim1Code = B.ItemDim1Code
AND LangCode = 'TR'
) DIM1
OUTER APPLY (
SELECT TOP 1 ColorDescription
FROM cdColorDesc
WHERE ColorCode = B.ColorCode
AND LangCode = 'TR'
) COL
ORDER BY
CASE
WHEN @p3 <> '' AND LTRIM(RTRIM(ISNULL(B.ColorCode, ''))) = @p3 THEN 0
WHEN @p3 = '' THEN 0
ELSE 1
END,
CASE
WHEN @p4 <> '' AND LTRIM(RTRIM(ISNULL(B.ItemDim1Code, ''))) = @p4 THEN 0
WHEN @p4 = '' THEN 0
ELSE 1
END,
B.InvoiceDate DESC,
B.InvoiceNumber DESC
`
return mssqlDB.QueryRowContext(ctx, sqlText, sKodu, costDate, colorCode, itemDim1Code), nil
}
func GetProductionHasCostPurchaseHistoryByExpenseCode(
ctx context.Context,
mssqlDB *sql.DB,
sKodu string,
costDate string,
limit int,
) (*sql.Rows, error) {
sKodu = strings.TrimSpace(sKodu)
costDate = strings.TrimSpace(costDate)
if limit <= 0 {
limit = 250
}
sqlText := `
WITH BASE AS (
SELECT
A.InvoiceDate,
A.InvoiceNumber,
A.ProcessCode,
A.CurrAccTypeCode,
A.CurrAccCode,
A.ItemTypeCode,
A.ItemCode,
A.ColorCode,
A.ItemDim1Code,
A.Qty1,
A.Doc_Price,
A.Doc_Amount,
A.Doc_CurrencyCode
FROM AllInvoicesWithAttributes A
WHERE A.ProcessCode IN ('BP')
AND A.ATAtt01 IN (1, 2)
AND A.CompanyCode IN (1, 2, 5)
AND A.IsCompleted = 1
AND YEAR(A.InvoiceDate) >= 2022
AND LTRIM(RTRIM(A.ItemCode)) = @p1
AND (ISNULL(A.Doc_Price, 0) > 0 OR ISNULL(A.Doc_Amount, 0) > 0)
AND (NULLIF(@p2, '') IS NULL OR CONVERT(date, A.InvoiceDate) < CONVERT(date, NULLIF(@p2, ''), 23))
)
SELECT TOP (@p3)
'purchase' AS sourceType,
'MAN' AS priceType,
CONVERT(VARCHAR(16), B.InvoiceDate, 120) AS Tarih,
ISNULL(B.InvoiceNumber, '') AS FaturaKodu,
ISNULL(B.CurrAccCode, '') AS FirmaKodu,
ISNULL(CAD.CurrAccDescription, '') AS FirmaAciklama,
LTRIM(RTRIM(ISNULL(B.ItemCode, ''))) AS MasrafKodu,
ISNULL(ID.ItemDescription, '') AS MasrafDetay,
ISNULL(B.ColorCode, '') AS ColorCode,
ISNULL(COL.ColorDescription, '') AS ColorDescription,
ISNULL(B.ItemDim1Code, '') AS ItemDim1Code,
ISNULL(DIM1.ItemDim1Description, '') AS ItemDim1Description,
ISNULL(B.Qty1, 0) AS Miktar,
CASE
WHEN B.ProcessCode = 'EP' THEN ''
ELSE ISNULL(CI.UnitOfMeasureCode1, '')
END AS BIRIM,
ISNULL(B.Doc_Price, 0) AS EvrakFiyat,
ISNULL(B.Doc_Amount, 0) AS EvrakTutar,
ISNULL(B.Doc_CurrencyCode, '') AS EvrakDoviz
FROM BASE B
LEFT JOIN cdItem CI
ON CI.ItemTypeCode = B.ItemTypeCode
AND CI.ItemCode = B.ItemCode
OUTER APPLY (
SELECT TOP 1 ItemDescription
FROM cdItemDesc
WHERE ItemTypeCode = B.ItemTypeCode
AND ItemCode = B.ItemCode
AND LangCode = 'TR'
) ID
OUTER APPLY (
SELECT TOP 1 ItemDim1Description
FROM cdItemDim1Desc
WHERE ItemDim1Code = B.ItemDim1Code
AND LangCode = 'TR'
) DIM1
OUTER APPLY (
SELECT TOP 1 ColorDescription
FROM cdColorDesc
WHERE ColorCode = B.ColorCode
AND LangCode = 'TR'
) COL
OUTER APPLY (
SELECT TOP 1 CurrAccDescription
FROM cdCurrAccDesc
WHERE CurrAccTypeCode = B.CurrAccTypeCode
AND CurrAccCode = B.CurrAccCode
AND LangCode = 'TR'
) CAD
ORDER BY
B.InvoiceDate DESC,
B.InvoiceNumber DESC
`
return mssqlDB.QueryContext(ctx, sqlText, sKodu, costDate, limit)
}
func GetProductionHasCostRecipeHistoryByExpenseCode(
ctx context.Context,
uretimDB *sql.DB,
currentOnMLNo int,
sKodu string,
colorCode string,
costDate string,
limit int,
) (*sql.Rows, error) {
sKodu = strings.TrimSpace(sKodu)
colorCode = strings.TrimSpace(colorCode)
costDate = strings.TrimSpace(costDate)
if limit <= 0 {
limit = 250
}
sqlText := `
SELECT TOP (@p5)
'recipe' AS sourceType,
ISNULL(NULLIF(LTRIM(RTRIM(D.sFiyatTipi)), ''), 'SAF') AS priceType,
CONVERT(VARCHAR(16), COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi), 120) AS dteIslemTarihi,
RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLNo, 0))) AS nOnMLNo,
ISNULL(UF.FirmaKodu, '') AS FirmaKodu,
ISNULL(UF.FirmaAciklama, '') AS FirmaAciklama,
ISNULL(D.sKodu, '') AS sKodu,
ISNULL(D.sAciklama, '') AS sAciklama,
ISNULL(D.sRenk, '') AS sRenk,
ISNULL(D.lMiktar, 0) AS lMiktar,
ISNULL(D.sBirim, '') AS sBirim,
CASE
WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0)
ELSE ISNULL(D.lDovizFiyati, 0)
END AS lDovizFiyati,
CASE
WHEN ISNULL(D.lDovizTutari, 0) > 0 THEN ISNULL(D.lDovizTutari, 0)
WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0) * ISNULL(D.lMiktar, 0)
ELSE ISNULL(D.lDovizFiyati, 0) * ISNULL(D.lMiktar, 0)
END AS lDovizTutari,
CASE
WHEN LTRIM(RTRIM(ISNULL(D.fiyat_doviz, ''))) <> '' THEN LTRIM(RTRIM(D.fiyat_doviz))
WHEN LTRIM(RTRIM(ISNULL(D.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(D.sDovizCinsi))
WHEN LTRIM(RTRIM(ISNULL(M.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(M.sDovizCinsi))
ELSE 'USD'
END AS USD,
ISNULL(NULLIF(LTRIM(RTRIM(T.sAciklama3)), ''), N'DUMMY') AS DUMMY
FROM dbo.spUrtOnMLMasDet D
INNER JOIN dbo.spUrtOnMLMas M
ON M.nOnMLNo = D.nOnMLNo
LEFT JOIN dbo.spUrtOnMLHammaddeTuru T
ON T.nHammaddeTuruNo = D.nHammaddeTuruNo
OUTER APPLY (
SELECT TOP 1
ISNULL(F.sKodu, '') AS FirmaKodu,
ISNULL(F.sAciklama, '') AS FirmaAciklama
FROM dbo.spUrtSiparisDet SD
INNER JOIN dbo.spUrtSiparis SM
ON SM.nUrtSiparisID = SD.nUrtSiparisID
LEFT JOIN dbo.tbFirma F
ON F.nFirmaID = SM.nFirmaID
WHERE (
(ISNULL(M.nUrtReceteID, 0) > 0 AND SD.nUrtReceteID = M.nUrtReceteID)
OR (ISNULL(M.nUrtReceteID, 0) <= 0 AND LTRIM(RTRIM(ISNULL(SD.sMModelKodu, ''))) = LTRIM(RTRIM(ISNULL(M.UrunKodu, ''))))
)
AND SD.dteIslemTarihi <= COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi)
ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC
) UF
WHERE LTRIM(RTRIM(D.sKodu)) = @p1
AND (@p2 <= 0 OR D.nOnMLNo <> @p2)
AND (
ISNULL(D.fiyat_girilen, 0) > 0
OR ISNULL(D.lDovizFiyati, 0) > 0
OR ISNULL(D.lDovizTutari, 0) > 0
)
AND (
NULLIF(@p3, '') IS NULL
OR CONVERT(date, COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi)) < CONVERT(date, NULLIF(@p3, ''), 23)
)
ORDER BY
CASE
WHEN @p4 <> '' AND LTRIM(RTRIM(ISNULL(D.sRenk, ''))) = @p4 THEN 0
WHEN @p4 = '' THEN 0
ELSE 1
END,
COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi) DESC,
D.nOnMLNo DESC,
D.nOnMLDetNo DESC
`
return uretimDB.QueryContext(ctx, sqlText, sKodu, currentOnMLNo, costDate, colorCode, limit)
}
func BuildProductionHasCostSimilarCodePrefix(sKodu string) string {
normalizedCode := strings.ToUpper(strings.TrimSpace(sKodu))
if normalizedCode == "" {
return ""
}
runes := []rune(normalizedCode)
if len(runes) <= 4 {
return normalizedCode
}
if len(runes) >= 5 && len(runes) > 1 && runes[1] == '.' {
return string(runes[:5])
}
return string(runes[:4])
}
func GetProductionHasCostPurchaseHistoryByCodePrefix(
ctx context.Context,
mssqlDB *sql.DB,
sKoduPrefix string,
costDate string,
limit int,
) (*sql.Rows, error) {
sKoduPrefix = strings.TrimSpace(sKoduPrefix)
costDate = strings.TrimSpace(costDate)
if limit <= 0 {
limit = 250
}
sqlText := `
WITH BASE AS (
SELECT
A.InvoiceDate,
A.InvoiceNumber,
A.ProcessCode,
A.CurrAccTypeCode,
A.CurrAccCode,
A.ItemTypeCode,
A.ItemCode,
A.ColorCode,
A.ItemDim1Code,
A.Qty1,
A.Doc_Price,
A.Doc_Amount,
A.Doc_CurrencyCode
FROM AllInvoicesWithAttributes A
WHERE A.ProcessCode IN ('BP')
AND A.ATAtt01 IN (1, 2)
AND A.CompanyCode IN (1, 2, 5)
AND A.IsCompleted = 1
AND YEAR(A.InvoiceDate) >= 2022
AND NULLIF(@p1, '') IS NOT NULL
AND LTRIM(RTRIM(A.ItemCode)) LIKE @p1 + '%'
AND (ISNULL(A.Doc_Price, 0) > 0 OR ISNULL(A.Doc_Amount, 0) > 0)
AND (NULLIF(@p2, '') IS NULL OR CONVERT(date, A.InvoiceDate) < CONVERT(date, NULLIF(@p2, ''), 23))
)
SELECT TOP (@p3)
'purchase' AS sourceType,
'BNZ' AS priceType,
CONVERT(VARCHAR(16), B.InvoiceDate, 120) AS Tarih,
ISNULL(B.InvoiceNumber, '') AS FaturaKodu,
ISNULL(B.CurrAccCode, '') AS FirmaKodu,
ISNULL(CAD.CurrAccDescription, '') AS FirmaAciklama,
LTRIM(RTRIM(ISNULL(B.ItemCode, ''))) AS MasrafKodu,
ISNULL(ID.ItemDescription, '') AS MasrafDetay,
ISNULL(B.ColorCode, '') AS ColorCode,
ISNULL(COL.ColorDescription, '') AS ColorDescription,
ISNULL(B.ItemDim1Code, '') AS ItemDim1Code,
ISNULL(DIM1.ItemDim1Description, '') AS ItemDim1Description,
ISNULL(B.Qty1, 0) AS Miktar,
CASE
WHEN B.ProcessCode = 'EP' THEN ''
ELSE ISNULL(CI.UnitOfMeasureCode1, '')
END AS BIRIM,
ISNULL(B.Doc_Price, 0) AS EvrakFiyat,
ISNULL(B.Doc_Amount, 0) AS EvrakTutar,
ISNULL(B.Doc_CurrencyCode, '') AS EvrakDoviz
FROM BASE B
LEFT JOIN cdItem CI
ON CI.ItemTypeCode = B.ItemTypeCode
AND CI.ItemCode = B.ItemCode
OUTER APPLY (
SELECT TOP 1 ItemDescription
FROM cdItemDesc
WHERE ItemTypeCode = B.ItemTypeCode
AND ItemCode = B.ItemCode
AND LangCode = 'TR'
) ID
OUTER APPLY (
SELECT TOP 1 ItemDim1Description
FROM cdItemDim1Desc
WHERE ItemDim1Code = B.ItemDim1Code
AND LangCode = 'TR'
) DIM1
OUTER APPLY (
SELECT TOP 1 ColorDescription
FROM cdColorDesc
WHERE ColorCode = B.ColorCode
AND LangCode = 'TR'
) COL
OUTER APPLY (
SELECT TOP 1 CurrAccDescription
FROM cdCurrAccDesc
WHERE CurrAccTypeCode = B.CurrAccTypeCode
AND CurrAccCode = B.CurrAccCode
AND LangCode = 'TR'
) CAD
ORDER BY
B.InvoiceDate DESC,
B.InvoiceNumber DESC
`
return mssqlDB.QueryContext(ctx, sqlText, sKoduPrefix, costDate, limit)
}
func GetProductionHasCostOnMLHistoryByCodePrefix(
ctx context.Context,
uretimDB *sql.DB,
sKoduPrefix string,
costDate string,
limit int,
) (*sql.Rows, error) {
sKoduPrefix = strings.TrimSpace(sKoduPrefix)
costDate = strings.TrimSpace(costDate)
if limit <= 0 {
limit = 250
}
sqlText := `
SELECT TOP (@p3)
'recipe' AS sourceType,
'BNZ' AS priceType,
CONVERT(VARCHAR(16), COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi), 120) AS dteIslemTarihi,
RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLNo, 0))) AS nOnMLNo,
ISNULL(UF.FirmaKodu, '') AS FirmaKodu,
ISNULL(UF.FirmaAciklama, '') AS FirmaAciklama,
ISNULL(D.sKodu, '') AS sKodu,
ISNULL(D.sAciklama, '') AS sAciklama,
ISNULL(D.sRenk, '') AS sRenk,
ISNULL(D.lMiktar, 0) AS lMiktar,
ISNULL(D.sBirim, '') AS sBirim,
CASE
WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0)
ELSE ISNULL(D.lDovizFiyati, 0)
END AS lDovizFiyati,
CASE
WHEN ISNULL(D.lDovizTutari, 0) > 0 THEN ISNULL(D.lDovizTutari, 0)
WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0) * ISNULL(D.lMiktar, 0)
ELSE ISNULL(D.lDovizFiyati, 0) * ISNULL(D.lMiktar, 0)
END AS lDovizTutari,
CASE
WHEN LTRIM(RTRIM(ISNULL(D.fiyat_doviz, ''))) <> '' THEN LTRIM(RTRIM(D.fiyat_doviz))
WHEN LTRIM(RTRIM(ISNULL(D.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(D.sDovizCinsi))
WHEN LTRIM(RTRIM(ISNULL(M.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(M.sDovizCinsi))
ELSE 'USD'
END AS USD,
ISNULL(NULLIF(LTRIM(RTRIM(D.sAciklama3)), ''), N'DUMMY') AS DUMMY
FROM dbo.spUrtOnMLMasDet D
INNER JOIN dbo.spUrtOnMLMas M
ON M.nOnMLNo = D.nOnMLNo
OUTER APPLY (
SELECT TOP 1
ISNULL(F.sKodu, '') AS FirmaKodu,
ISNULL(F.sAciklama, '') AS FirmaAciklama
FROM dbo.spUrtSiparisDet SD
INNER JOIN dbo.spUrtSiparis SM
ON SM.nUrtSiparisID = SD.nUrtSiparisID
LEFT JOIN dbo.tbFirma F
ON F.nFirmaID = SM.nFirmaID
WHERE (
(ISNULL(M.nUrtReceteID, 0) > 0 AND SD.nUrtReceteID = M.nUrtReceteID)
OR (ISNULL(M.nUrtReceteID, 0) <= 0 AND LTRIM(RTRIM(ISNULL(SD.sMModelKodu, ''))) = LTRIM(RTRIM(ISNULL(M.UrunKodu, ''))))
)
AND SD.dteIslemTarihi <= COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi)
ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC
) UF
WHERE NULLIF(@p1, '') IS NOT NULL
AND LTRIM(RTRIM(ISNULL(D.sKodu, ''))) LIKE @p1 + '%'
AND (
ISNULL(D.fiyat_girilen, 0) > 0
OR ISNULL(D.lDovizFiyati, 0) > 0
OR ISNULL(D.lDovizTutari, 0) > 0
)
AND (
NULLIF(@p2, '') IS NULL
OR CONVERT(date, COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi)) < CONVERT(date, NULLIF(@p2, ''), 23)
)
ORDER BY
COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi) DESC,
D.nOnMLNo DESC,
D.nOnMLDetNo DESC
`
return uretimDB.QueryContext(ctx, sqlText, sKoduPrefix, costDate, limit)
}
func GetProductionHasCostOnMLHistoryByHammaddeTuruNo(
ctx context.Context,
uretimDB *sql.DB,
nHammaddeTuruNo string,
costDate string,
limit int,
) (*sql.Rows, error) {
nHammaddeTuruNo = strings.TrimSpace(nHammaddeTuruNo)
costDate = strings.TrimSpace(costDate)
if limit <= 0 {
limit = 250
}
sqlText := `
SELECT TOP (@p3)
'recipe' AS sourceType,
'BNZ' AS priceType,
CONVERT(VARCHAR(16), COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi), 120) AS dteIslemTarihi,
RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLNo, 0))) AS nOnMLNo,
ISNULL(UF.FirmaKodu, '') AS FirmaKodu,
ISNULL(UF.FirmaAciklama, '') AS FirmaAciklama,
ISNULL(D.sKodu, '') AS sKodu,
ISNULL(D.sAciklama, '') AS sAciklama,
ISNULL(D.sRenk, '') AS sRenk,
ISNULL(D.lMiktar, 0) AS lMiktar,
ISNULL(D.sBirim, '') AS sBirim,
CASE
WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0)
ELSE ISNULL(D.lDovizFiyati, 0)
END AS lDovizFiyati,
CASE
WHEN ISNULL(D.lDovizTutari, 0) > 0 THEN ISNULL(D.lDovizTutari, 0)
WHEN ISNULL(D.fiyat_girilen, 0) > 0 THEN ISNULL(D.fiyat_girilen, 0) * ISNULL(D.lMiktar, 0)
ELSE ISNULL(D.lDovizFiyati, 0) * ISNULL(D.lMiktar, 0)
END AS lDovizTutari,
CASE
WHEN LTRIM(RTRIM(ISNULL(D.fiyat_doviz, ''))) <> '' THEN LTRIM(RTRIM(D.fiyat_doviz))
WHEN LTRIM(RTRIM(ISNULL(D.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(D.sDovizCinsi))
WHEN LTRIM(RTRIM(ISNULL(M.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(M.sDovizCinsi))
ELSE 'USD'
END AS USD,
ISNULL(NULLIF(LTRIM(RTRIM(D.sAciklama3)), ''), N'DUMMY') AS DUMMY
FROM dbo.spUrtOnMLMasDet D
INNER JOIN dbo.spUrtOnMLMas M
ON M.nOnMLNo = D.nOnMLNo
OUTER APPLY (
SELECT TOP 1
ISNULL(F.sKodu, '') AS FirmaKodu,
ISNULL(F.sAciklama, '') AS FirmaAciklama
FROM dbo.spUrtSiparisDet SD
INNER JOIN dbo.spUrtSiparis SM
ON SM.nUrtSiparisID = SD.nUrtSiparisID
LEFT JOIN dbo.tbFirma F
ON F.nFirmaID = SM.nFirmaID
WHERE (
(ISNULL(M.nUrtReceteID, 0) > 0 AND SD.nUrtReceteID = M.nUrtReceteID)
OR (ISNULL(M.nUrtReceteID, 0) <= 0 AND LTRIM(RTRIM(ISNULL(SD.sMModelKodu, ''))) = LTRIM(RTRIM(ISNULL(M.UrunKodu, ''))))
)
AND SD.dteIslemTarihi <= COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi)
ORDER BY SD.dteIslemTarihi DESC, SD.nUrtSiparisID DESC
) UF
WHERE D.nHammaddeTuruNo = @p1
AND ISNULL(D.fiyat_girilen, 0) > 0
AND (
NULLIF(@p2, '') IS NULL
OR CONVERT(date, COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi)) < CONVERT(date, NULLIF(@p2, ''), 23)
)
ORDER BY
COALESCE(D.dteIslemTarihiDeg, D.dteIslemTarihi, M.Tarihi, M.dteKayitTarihi) DESC,
D.nOnMLNo DESC,
D.nOnMLDetNo DESC
`
return uretimDB.QueryContext(ctx, sqlText, nHammaddeTuruNo, costDate, limit)
}
func GetProductionHasCostSimilarItemHistory(
ctx context.Context,
mssqlDB *sql.DB,
uretimDB *sql.DB,
nHammaddeTuruNo string,
costDate string,
limit int,
) ([]any, error) {
if limit <= 0 {
limit = 50
}
// 1. Satinalma (V3) tarafini sorgula - Simdilik V3 tarafi icin hammadde turu eslestirmesi belirsiz oldugundan pasif
/*
v3Sql := `
SELECT TOP (@p2)
'purchase' AS sourceType,
'BNZ' AS priceType,
CONVERT(VARCHAR(16), A.InvoiceDate, 120) AS Tarih,
ISNULL(A.InvoiceNumber, '') AS FaturaKodu,
LTRIM(RTRIM(ISNULL(A.ItemCode, ''))) AS MasrafKodu,
ISNULL(ID.ItemDescription, '') AS MasrafDetay,
ISNULL(A.ColorCode, '') AS ColorCode,
ISNULL(A.Qty1, 0) AS Miktar,
ISNULL(CI.UnitOfMeasureCode1, '') AS BIRIM,
ISNULL(A.Doc_Price, 0) AS EvrakFiyat,
ISNULL(A.Doc_CurrencyCode, '') AS EvrakDoviz
FROM AllInvoicesWithAttributes A
LEFT JOIN cdItem CI ON CI.ItemTypeCode = A.ItemTypeCode AND CI.ItemCode = A.ItemCode
OUTER APPLY (
SELECT TOP 1 ItemDescription FROM cdItemDesc
WHERE ItemTypeCode = A.ItemTypeCode AND ItemCode = A.ItemCode AND LangCode = 'TR'
) ID
WHERE A.ProcessCode IN ('BP')
AND A.ATAtt01 IN (1, 2)
AND A.CompanyCode IN (1, 2, 5)
AND A.IsCompleted = 1
AND YEAR(A.InvoiceDate) >= 2023
AND (NULLIF(@p1, '') IS NULL OR CONVERT(date, A.InvoiceDate) < CONVERT(date, NULLIF(@p1, ''), 23))
AND EXISTS (
-- Hammadde turu eslestirmesi (V3 tarafindaki karsiligi varsa)
SELECT 1 FROM cdItem WHERE ItemCode = A.ItemCode
)
ORDER BY A.InvoiceDate DESC
`
*/
// 2. Uretim (Recete) tarafini sorgula
uretimSql := `
SELECT TOP (@p3)
'recipe' AS sourceType,
'BNZ' AS priceType,
CONVERT(VARCHAR(16), ISNULL(M.Tarihi, M.dteKayitTarihi), 120) AS dteIslemTarihi,
RTRIM(CONVERT(VARCHAR(32), ISNULL(D.nOnMLNo, 0))) AS nOnMLNo,
ISNULL(D.sKodu, '') AS sKodu,
ISNULL(D.sAciklama, '') AS sAciklama,
ISNULL(D.sRenk, '') AS sRenk,
ISNULL(D.lMiktar, 0) AS lMiktar,
ISNULL(D.sBirim, '') AS sBirim,
ISNULL(D.lDovizFiyati, 0) AS lDovizFiyati,
CASE
WHEN LTRIM(RTRIM(ISNULL(D.fiyat_doviz, ''))) <> '' THEN LTRIM(RTRIM(D.fiyat_doviz))
WHEN LTRIM(RTRIM(ISNULL(M.sDovizCinsi, ''))) <> '' THEN LTRIM(RTRIM(M.sDovizCinsi))
ELSE 'USD'
END AS USD
FROM dbo.spUrtOnMLMasDet D
INNER JOIN dbo.spUrtOnMLMas M ON M.nOnMLNo = D.nOnMLNo
WHERE D.nHammaddeTuruNo = @p1
AND (NULLIF(@p2, '') IS NULL OR CONVERT(date, ISNULL(M.Tarihi, M.dteKayitTarihi)) < CONVERT(date, NULLIF(@p2, ''), 23))
ORDER BY ISNULL(M.Tarihi, M.dteKayitTarihi) DESC
`
// Not: nHammaddeTuruNo parametresine gore sadece Reçete tarafı şu an doğrudan filtrelenebiliyor.
// V3 tarafı için ItemTypeCode veya özel bir grup kodu gerekebilir.
// Kullanıcının talebi üzerine Reçete (URETIM) odaklı sorguyu önceliklendiriyoruz.
rows, err := uretimDB.QueryContext(ctx, uretimSql, nHammaddeTuruNo, costDate, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var results []any
for rows.Next() {
// Basit bir map veya struct ile dondurebiliriz
var row struct {
SourceType string `json:"sourceType"`
PriceType string `json:"priceType"`
Tarih string `json:"Tarih"`
EvrakKodu string `json:"EvrakKodu"`
Kod string `json:"Kod"`
Aciklama string `json:"Aciklama"`
Renk string `json:"Renk"`
Miktar float64 `json:"Miktar"`
Birim string `json:"Birim"`
Fiyat float64 `json:"Fiyat"`
Doviz string `json:"Doviz"`
}
if err := rows.Scan(
&row.SourceType, &row.PriceType, &row.Tarih, &row.EvrakKodu,
&row.Kod, &row.Aciklama, &row.Renk, &row.Miktar, &row.Birim,
&row.Fiyat, &row.Doviz,
); err == nil {
results = append(results, row)
}
}
return results, nil
}

View File

@@ -760,7 +760,16 @@ func getOrderLinesFromDB(db *sql.DB, orderID string) ([]OrderLineRaw, error) {
P.ProductAtt01Desc,
P.ProductAtt02Desc,
P.ProductAtt44Desc,
L.IsClosed,
CASE
WHEN ISNULL(L.IsClosed, 0) = 1
OR EXISTS (
SELECT 1
FROM BAGGI_V3.dbo.trInvoiceLine il WITH (NOLOCK)
WHERE il.OrderLineID = L.OrderLineID
)
THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS IsClosed,
L.WithHoldingTaxTypeCode,
L.DOVCode,
L.PlannedDateOfLading,

View File

@@ -0,0 +1,2048 @@
package routes
import (
"bssapp-backend/auth"
"bssapp-backend/db"
"bssapp-backend/models"
"bssapp-backend/queries"
"bssapp-backend/utils"
"context"
"database/sql"
"encoding/json"
"log"
"net/http"
"strconv"
"strings"
"time"
)
func logProductionHasCostDetailEditorOptionItemDiagnostics(ctx context.Context, uretimDB *sql.DB, search string, limit int) {
logger := utils.SlogFromContext(ctx).With(
"handler", "production-product-costing.detail-editor-options.diagnostics",
"search", search,
"limit", limit,
)
expectedColumns := []string{
"nStokID",
"sKodu",
"sAciklama",
"sModel",
"sBirimCinsi1",
"IsBlocked",
}
probes := []struct {
name string
sqlText string
}{
{
name: "projection:nStokID",
sqlText: `SELECT TOP 1 RTRIM(CONVERT(VARCHAR(32), ISNULL(S.nStokID, 0))) FROM dbo.tbStok S`,
},
{
name: "projection:sKodu",
sqlText: `SELECT TOP 1 LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sKodu, '')))) FROM dbo.tbStok S`,
},
{
name: "projection:sAciklama",
sqlText: `SELECT TOP 1 LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sAciklama, '')))) FROM dbo.tbStok S`,
},
{
name: "projection:sModel",
sqlText: `SELECT TOP 1 LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) FROM dbo.tbStok S`,
},
{
name: "projection:sBirimCinsi1",
sqlText: `SELECT TOP 1 LTRIM(RTRIM(CONVERT(NVARCHAR(64), ISNULL(S.sBirimCinsi1, '')))) FROM dbo.tbStok S`,
},
{
name: "projection:IsBlocked",
sqlText: `SELECT TOP 1 RTRIM(CONVERT(VARCHAR(32), ISNULL(S.IsBlocked, 0))) FROM dbo.tbStok S`,
},
{
name: "filter:model_like_count",
sqlText: `SELECT RTRIM(CONVERT(VARCHAR(32), COUNT(1))) FROM dbo.tbStok S WHERE LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) LIKE '_.%'`,
},
{
name: "filter:isblocked_count",
sqlText: `SELECT RTRIM(CONVERT(VARCHAR(32), COUNT(1))) FROM dbo.tbStok S WHERE ISNULL(S.IsBlocked, 0) = 0`,
},
{
name: "filter:final_count",
sqlText: `SELECT RTRIM(CONVERT(VARCHAR(32), COUNT(1))) FROM dbo.tbStok S WHERE ISNULL(S.IsBlocked, 0) = 0 AND LTRIM(RTRIM(CONVERT(NVARCHAR(255), ISNULL(S.sModel, '')))) LIKE '_.%'`,
},
}
log.Printf("[ProductionHasCostDetailEditorOptions] item diagnostics start search=%q limit=%d", search, limit)
for _, columnName := range expectedColumns {
var exists int
err := uretimDB.QueryRowContext(
ctx,
`SELECT COUNT(1)
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'dbo'
AND TABLE_NAME = 'tbStok'
AND COLUMN_NAME = @p1`,
columnName,
).Scan(&exists)
if err != nil {
logger.Error("query error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] item diagnostics column check error column=%s err=%v", columnName, err)
continue
}
log.Printf("[ProductionHasCostDetailEditorOptions] item diagnostics column=%s exists=%t", columnName, exists > 0)
}
for _, probe := range probes {
var sample sql.NullString
err := uretimDB.QueryRowContext(ctx, probe.sqlText).Scan(&sample)
if err != nil {
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] item diagnostics probe=%s err=%v", probe.name, err)
continue
}
log.Printf("[ProductionHasCostDetailEditorOptions] item diagnostics probe=%s sample=%q", probe.name, strings.TrimSpace(sample.String))
}
log.Printf("[ProductionHasCostDetailEditorOptions] item diagnostics end search=%q limit=%d", search, limit)
}
// GET /api/pricing/production-product-costing/no-cost-products
func GetProductionNoCostProductsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
search := strings.TrimSpace(r.URL.Query().Get("search"))
fromDate := strings.TrimSpace(r.URL.Query().Get("from_date"))
rows, err := queries.GetProductionNoCostProducts(r.Context(), uretimDB, fromDate, search)
if err != nil {
log.Printf("❌ [ProductionNoCost] query error: %v", err)
http.Error(w, "Veritabanı hatası", http.StatusInternalServerError)
return
}
defer rows.Close()
list := make([]models.ProductionNoCostProductRow, 0, 200)
for rows.Next() {
var item models.ProductionNoCostProductRow
if err := rows.Scan(
&item.UretimSekli,
&item.UrtSiparisNo,
&item.IslemTarihi,
&item.FirmaKodu,
&item.FirmaAdi,
&item.SonIsEmriVeren,
&item.MMiktarG,
&item.MModelKodu,
&item.Kodu,
&item.ModelAdi,
&item.SKullaniciAdi,
&item.SKullaniciGunc,
); err != nil {
log.Printf("⚠️ [ProductionNoCost] scan error: %v", err)
continue
}
list = append(list, item)
}
if err := rows.Err(); err != nil {
log.Printf("⚠️ [ProductionNoCost] rows error: %v", err)
http.Error(w, "Veritabanı satır hatası", http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(list)
}
// GET /api/pricing/production-product-costing/has-cost-products
func GetProductionHasCostProductsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
search := strings.TrimSpace(r.URL.Query().Get("search"))
offset := parsePositiveIntOrDefault(r.URL.Query().Get("offset"), 0)
limit := parsePositiveIntOrDefault(r.URL.Query().Get("limit"), 300)
if limit > 1000 {
limit = 1000
}
rows, err := queries.GetProductionHasCostProducts(r.Context(), uretimDB, search, offset, limit)
if err != nil {
log.Printf("❌ [ProductionHasCost] query error: %v", err)
http.Error(w, "Veritabanı hatası", http.StatusInternalServerError)
return
}
defer rows.Close()
list := make([]models.ProductionHasCostProductRow, 0, 200)
for rows.Next() {
var item models.ProductionHasCostProductRow
if err := rows.Scan(
&item.UretimSekli,
&item.NOnMLNo,
&item.UrunKodu,
&item.UrunAdi,
&item.Tarihi,
&item.DteKayitTarihi,
&item.SKullaniciAdi,
&item.LTutarTL,
&item.LTutarUSD,
&item.LTutarEURO,
&item.DteGuncellemeTarihi,
&item.SGuncellemeKullaniciAdi,
&item.NUrtReceteID,
&item.SAciklama,
&item.SonSiparisTarihi,
&item.MaliyetDurumu,
); err != nil {
log.Printf("⚠️ [ProductionHasCost] scan error: %v", err)
continue
}
list = append(list, item)
}
if err := rows.Err(); err != nil {
log.Printf("⚠️ [ProductionHasCost] rows error: %v", err)
http.Error(w, "Veritabanı satır hatası", http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(list)
}
// GET /api/pricing/production-product-costing/has-cost-history
func GetProductionHasCostHistoryHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
productCode := strings.TrimSpace(r.URL.Query().Get("urun_kodu"))
if productCode == "" {
http.Error(w, "urun_kodu zorunlu", http.StatusBadRequest)
return
}
rows, err := queries.GetProductionHasCostHistoryByProductCode(r.Context(), uretimDB, productCode)
if err != nil {
log.Printf("❌ [ProductionHasCostHistory] query error: %v", err)
http.Error(w, "Veritabanı hatası", http.StatusInternalServerError)
return
}
defer rows.Close()
list := make([]models.ProductionHasCostHistoryRow, 0, 100)
for rows.Next() {
var item models.ProductionHasCostHistoryRow
if err := rows.Scan(
&item.NOnMLNo,
&item.UrunKodu,
&item.UrunAdi,
&item.Tarihi,
&item.SKullaniciAdi,
&item.LTutarUSD,
&item.LTutarTL,
&item.LTutarEURO,
&item.SDovizCinsi,
&item.LTutarDoviz,
&item.DteGuncellemeTarihi,
&item.SGuncellemeKullaniciAdi,
&item.NUrtReceteID,
&item.SAciklama,
); err != nil {
log.Printf("⚠️ [ProductionHasCostHistory] scan error: %v", err)
continue
}
list = append(list, item)
}
if err := rows.Err(); err != nil {
log.Printf("⚠️ [ProductionHasCostHistory] rows error: %v", err)
http.Error(w, "Veritabanı satır hatası", http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(list)
}
// GET /api/pricing/production-product-costing/has-cost-detail-groups
func GetProductionHasCostDetailGroupsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
detailSource := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("detail_source")))
recipeCode := strings.TrimSpace(r.URL.Query().Get("recete_kodu"))
productCode := strings.TrimSpace(r.URL.Query().Get("urun_kodu"))
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
logger := utils.SlogFromContext(ctx).With(
"handler", "production-product-costing.detail-groups",
"detail_source", detailSource,
"urun_kodu", productCode,
"recete_kodu", recipeCode,
)
if detailSource == "no-cost" || recipeCode != "" {
if recipeCode == "" {
logger.Warn("request invalid", "reason", "missing recete_kodu")
http.Error(w, "recete_kodu zorunlu", http.StatusBadRequest)
return
}
logger.Info("request start")
rows, err := queries.GetProductionNoCostDetailRowsByRecipeCode(ctx, uretimDB, recipeCode, productCode)
if err != nil {
logger.Error("query error", "err", err)
log.Printf("❌ [ProductionNoCostDetailGroups] query error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
defer rows.Close()
groups := make([]models.ProductionHasCostDetailGroup, 0, 16)
groupIndexByName := map[string]int{}
scannedRows := 0
scanErrors := 0
for rows.Next() {
var (
groupName string
groupTotal float64
groupTotalUSD float64
fiyatGirilen sql.NullFloat64
fiyatDoviz sql.NullString
maliyeteDahil sql.NullBool
cmPriceTypeID sql.NullInt64
item models.ProductionHasCostDetailGroupItem
)
if err := rows.Scan(
&groupName,
&groupTotal,
&groupTotalUSD,
&item.NOnMLNo,
&item.NOnMLDetNo,
&item.NHammaddeTuruNo,
&item.SKodu,
&item.SAciklama,
&item.SRenk,
&item.SBeden,
&item.SAciklama2,
&item.LMiktar,
&item.LFiyat,
&item.LTutar,
&item.SFiyatTipi,
&item.SDovizCinsi,
&item.LDovizKuru,
&item.LDovizFiyati,
&fiyatGirilen,
&fiyatDoviz,
&maliyeteDahil,
&cmPriceTypeID,
&item.USDTutar,
&item.EURTutar,
&item.GBPTutar,
&item.SBirim,
&item.SHammaddeTuruAdi,
&item.SParcaAdi,
); err != nil {
scanErrors += 1
logger.Warn("scan error", "scan_index", scannedRows+scanErrors+1, "err", err)
log.Printf("⚠️ [ProductionNoCostDetailGroups] scan error: %v", err)
continue
}
scannedRows += 1
if fiyatGirilen.Valid {
item.FiyatGirilen = new(float64)
*item.FiyatGirilen = fiyatGirilen.Float64
}
if fiyatDoviz.Valid {
item.FiyatDoviz = strings.TrimSpace(fiyatDoviz.String)
}
item.MaliyeteDahil = !maliyeteDahil.Valid || maliyeteDahil.Bool
if cmPriceTypeID.Valid {
value := int(cmPriceTypeID.Int64)
item.CMPriceTypeID = &value
}
idx, ok := groupIndexByName[groupName]
if !ok {
groups = append(groups, models.ProductionHasCostDetailGroup{
SAciklama3: groupName,
TotalTutar: groupTotal,
TotalUSDTutar: groupTotalUSD,
Items: make([]models.ProductionHasCostDetailGroupItem, 0, 8),
})
idx = len(groups) - 1
groupIndexByName[groupName] = idx
}
groups[idx].Items = append(groups[idx].Items, item)
}
if err := rows.Err(); err != nil {
logger.Error("rows error", "err", err)
log.Printf("⚠️ [ProductionNoCostDetailGroups] rows error: %v", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "group_count", len(groups), "row_count", scannedRows, "scan_errors", scanErrors)
log.Printf("[ProductionNoCostDetailGroups] done recete_kodu=%s groups=%d", recipeCode, len(groups))
_ = json.NewEncoder(w).Encode(groups)
return
}
rawOnMLNo := strings.TrimSpace(r.URL.Query().Get("n_onml_no"))
nOnMLNo, err := strconv.Atoi(rawOnMLNo)
if err != nil || nOnMLNo <= 0 {
logger.Warn("request invalid", "reason", "invalid n_onml_no", "raw_n_onml_no", rawOnMLNo)
http.Error(w, "n_onml_no zorunlu ve pozitif sayi olmali", http.StatusBadRequest)
return
}
logger = logger.With("n_onml_no", nOnMLNo)
logger.Info("request start")
log.Printf("[ProductionHasCostDetailGroups] start n_onml_no=%d", nOnMLNo)
rows, err := queries.GetProductionHasCostDetailRowsByOnMLNo(ctx, uretimDB, nOnMLNo)
if err != nil {
logger.Error("query error", "err", err)
log.Printf("❌ [ProductionHasCostDetailGroups] query error: %v", err)
http.Error(w, "Veritabanı hatası", http.StatusInternalServerError)
return
}
defer rows.Close()
groups := make([]models.ProductionHasCostDetailGroup, 0, 16)
groupIndexByName := map[string]int{}
scannedRows := 0
scanErrors := 0
for rows.Next() {
var (
groupName string
groupTotal float64
groupTotalUSD float64
fiyatGirilen sql.NullFloat64
fiyatDoviz sql.NullString
maliyeteDahil sql.NullBool
cmPriceTypeID sql.NullInt64
item models.ProductionHasCostDetailGroupItem
)
if err := rows.Scan(
&groupName,
&groupTotal,
&groupTotalUSD,
&item.NOnMLNo,
&item.NOnMLDetNo,
&item.NHammaddeTuruNo,
&item.SKodu,
&item.SAciklama,
&item.SRenk,
&item.SBeden,
&item.SAciklama2,
&item.LMiktar,
&item.LFiyat,
&item.LTutar,
&item.SFiyatTipi,
&item.SDovizCinsi,
&item.LDovizKuru,
&item.LDovizFiyati,
&fiyatGirilen,
&fiyatDoviz,
&maliyeteDahil,
&cmPriceTypeID,
&item.USDTutar,
&item.EURTutar,
&item.GBPTutar,
&item.SBirim,
&item.SHammaddeTuruAdi,
&item.SParcaAdi,
); err != nil {
log.Printf("⚠️ [ProductionHasCostDetailGroups] scan error: %v", err)
continue
}
scannedRows += 1
if fiyatGirilen.Valid {
item.FiyatGirilen = new(float64)
*item.FiyatGirilen = fiyatGirilen.Float64
}
if fiyatDoviz.Valid {
item.FiyatDoviz = strings.TrimSpace(fiyatDoviz.String)
}
item.MaliyeteDahil = maliyeteDahil.Valid && maliyeteDahil.Bool
if cmPriceTypeID.Valid {
value := int(cmPriceTypeID.Int64)
item.CMPriceTypeID = &value
}
idx, ok := groupIndexByName[groupName]
if !ok {
groups = append(groups, models.ProductionHasCostDetailGroup{
SAciklama3: groupName,
TotalTutar: groupTotal,
TotalUSDTutar: groupTotalUSD,
Items: make([]models.ProductionHasCostDetailGroupItem, 0, 24),
})
idx = len(groups) - 1
groupIndexByName[groupName] = idx
}
groups[idx].Items = append(groups[idx].Items, item)
}
if err := rows.Err(); err != nil {
log.Printf("⚠️ [ProductionHasCostDetailGroups] rows error: %v", err)
http.Error(w, "Veritabanı satır hatası", http.StatusInternalServerError)
return
}
logger.Info("request done", "group_count", len(groups), "row_count", scannedRows, "scan_errors", scanErrors)
log.Printf("[ProductionHasCostDetailGroups] done n_onml_no=%d groups=%d rows=%d scan_errors=%d", nOnMLNo, len(groups), scannedRows, scanErrors)
_ = json.NewEncoder(w).Encode(groups)
}
// GET /api/pricing/production-product-costing/has-cost-detail-header
func GetProductionHasCostDetailHeaderHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
mssqlDB := db.GetDB()
detailSource := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("detail_source")))
recipeCode := strings.TrimSpace(r.URL.Query().Get("recete_kodu"))
productCode := strings.TrimSpace(r.URL.Query().Get("urun_kodu"))
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
logger := utils.SlogFromContext(ctx).With(
"handler", "production-product-costing.detail-header",
"detail_source", detailSource,
"urun_kodu", productCode,
"recete_kodu", recipeCode,
)
if detailSource == "no-cost" || recipeCode != "" {
if recipeCode == "" {
logger.Warn("request invalid", "reason", "missing recete_kodu")
http.Error(w, "recete_kodu zorunlu", http.StatusBadRequest)
return
}
logger.Info("request start")
row, err := queries.GetProductionNoCostDetailHeaderByRecipeCode(ctx, uretimDB, recipeCode, productCode)
if err != nil {
logger.Error("query prepare error", "err", err)
log.Printf("❌ [ProductionNoCostDetailHeader] query prepare error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
var item models.ProductionHasCostDetailHeader
if err := row.Scan(
&item.UretimiYapanFirma,
&item.SonIsEmriVeren,
&item.NOnMLNo,
&item.UrunKodu,
&item.UrunAdi,
&item.UretimSekliID,
&item.UretimSekli,
&item.DteKayitTarihi,
&item.SKullaniciAdi,
&item.LTutarTL,
&item.LTutarUSD,
&item.LTutarEURO,
&item.LTutarGBP,
&item.SDovizCinsi,
&item.LTutarDoviz,
&item.DteGuncellemeTarihi,
&item.SGuncellemeKullaniciAdi,
&item.NUrtReceteID,
); err != nil {
logger.Warn("scan or not found", "err", err)
if err == sql.ErrNoRows {
logger.Warn("row not found")
http.Error(w, "Kayit bulunamadi", http.StatusNotFound)
return
}
log.Printf("❌ [ProductionNoCostDetailHeader] scan error: %v", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "n_urt_recete_id", item.NUrtReceteID, "urun_kodu", item.UrunKodu)
if mssqlDB != nil {
ana, alt, err := queries.GetProductAnaAltGrupByUrunKodu(ctx, mssqlDB, item.UrunKodu)
if err != nil {
logger.Warn("product group query error", "err", err)
} else {
item.UrunAnaGrubu = ana
item.UrunAltGrubu = alt
}
}
_ = json.NewEncoder(w).Encode(item)
return
}
rawOnMLNo := strings.TrimSpace(r.URL.Query().Get("n_onml_no"))
nOnMLNo, err := strconv.Atoi(rawOnMLNo)
if err != nil || nOnMLNo <= 0 {
logger.Warn("request invalid", "reason", "invalid n_onml_no", "raw_n_onml_no", rawOnMLNo)
http.Error(w, "n_onml_no zorunlu ve pozitif sayi olmali", http.StatusBadRequest)
return
}
logger = logger.With("n_onml_no", nOnMLNo)
logger.Info("request start")
row, err := queries.GetProductionHasCostDetailHeaderByOnMLNo(ctx, uretimDB, nOnMLNo)
if err != nil {
logger.Error("query prepare error", "err", err)
log.Printf("❌ [ProductionHasCostDetailHeader] query prepare error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
var item models.ProductionHasCostDetailHeader
if err := row.Scan(
&item.UretimiYapanFirma,
&item.SonIsEmriVeren,
&item.NOnMLNo,
&item.UrunKodu,
&item.UrunAdi,
&item.UretimSekliID,
&item.UretimSekli,
&item.DteKayitTarihi,
&item.SKullaniciAdi,
&item.LTutarTL,
&item.LTutarUSD,
&item.LTutarEURO,
&item.LTutarGBP,
&item.SDovizCinsi,
&item.LTutarDoviz,
&item.DteGuncellemeTarihi,
&item.SGuncellemeKullaniciAdi,
&item.NUrtReceteID,
); err != nil {
logger.Warn("scan or not found", "err", err)
if err == sql.ErrNoRows {
http.Error(w, "Kayit bulunamadi", http.StatusNotFound)
return
}
log.Printf("❌ [ProductionHasCostDetailHeader] scan error: %v", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "n_onml_no", item.NOnMLNo, "urun_kodu", item.UrunKodu, "n_urt_recete_id", item.NUrtReceteID)
if mssqlDB != nil {
ana, alt, err := queries.GetProductAnaAltGrupByUrunKodu(ctx, mssqlDB, item.UrunKodu)
if err != nil {
logger.Warn("product group query error", "err", err)
} else {
item.UrunAnaGrubu = ana
item.UrunAltGrubu = alt
}
}
_ = json.NewEncoder(w).Encode(item)
}
// GET /api/pricing/production-product-costing/production-types
func GetProductionTypesHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
logger := utils.SlogFromContext(ctx).With("handler", "production-product-costing.production-types")
logger.Info("request start")
rows, err := queries.GetProductionTypes(ctx, uretimDB)
if err != nil {
logger.Error("query error", "err", err)
log.Printf("❌ [ProductionTypes] query error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
defer rows.Close()
var types []models.ProductionType
for rows.Next() {
var t models.ProductionType
if err := rows.Scan(&t.ID, &t.Aciklama); err != nil {
logger.Warn("scan error", "err", err)
log.Printf("⚠️ [ProductionTypes] scan error: %v", err)
continue
}
types = append(types, t)
}
if err := rows.Err(); err != nil {
logger.Error("rows error", "err", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "row_count", len(types))
_ = json.NewEncoder(w).Encode(types)
}
// GET /api/pricing/production-product-costing/detail-editor-options
func GetProductionHasCostDetailEditorOptionsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
kind := strings.ToLower(strings.TrimSpace(r.URL.Query().Get("kind")))
search := strings.TrimSpace(r.URL.Query().Get("search"))
limit := parsePositiveIntOrDefault(r.URL.Query().Get("limit"), 100)
if limit > 200 {
limit = 200
}
logger := utils.SlogFromContext(ctx).With(
"handler", "production-product-costing.detail-editor-options",
"kind", kind,
"search", search,
"limit", limit,
)
logger.Info("request start")
switch kind {
case "hammadde":
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
rows, err := queries.GetProductionHasCostDetailHammaddeTypeOptions(ctx, uretimDB, search, limit)
if err != nil {
logger.Error("hammadde query error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] hammadde query error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
defer rows.Close()
if columns, columnErr := rows.Columns(); columnErr != nil {
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] item columns read error search=%q limit=%d err=%v", search, limit, columnErr)
} else {
log.Printf("[ProductionHasCostDetailEditorOptions] item columns=%v", columns)
}
list := make([]models.ProductionHasCostDetailEditorOption, 0, limit)
for rows.Next() {
var item models.ProductionHasCostDetailEditorOption
if err := rows.Scan(&item.NHammaddeTuruNo, &item.SHammaddeTuruAdi, &item.SAciklama3); err != nil {
logger.Warn("hammadde scan error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] hammadde scan error: %v", err)
continue
}
item.Kind = "hammadde"
item.Value = item.NHammaddeTuruNo
item.Label = strings.TrimSpace(item.NHammaddeTuruNo + " - " + item.SHammaddeTuruAdi)
item.SParcaAdi = item.SAciklama3
list = append(list, item)
}
if err := rows.Err(); err != nil {
logger.Error("hammadde rows error", "err", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "kind", "hammadde", "row_count", len(list))
_ = json.NewEncoder(w).Encode(list)
return
case "item":
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
log.Printf("[ProductionHasCostDetailEditorOptions] item start search=%q limit=%d", search, limit)
rows, err := queries.GetProductionHasCostDetailItemOptions(ctx, uretimDB, search, limit)
if err != nil {
logger.Error("item query error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] item query error search=%q limit=%d err=%v", search, limit, err)
logProductionHasCostDetailEditorOptionItemDiagnostics(ctx, uretimDB, search, limit)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
defer rows.Close()
if columns, columnErr := rows.Columns(); columnErr != nil {
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] item columns read error search=%q limit=%d err=%v", search, limit, columnErr)
} else {
log.Printf("[ProductionHasCostDetailEditorOptions] item columns=%v", columns)
}
list := make([]models.ProductionHasCostDetailEditorOption, 0, limit)
scanErrors := 0
for rows.Next() {
var item models.ProductionHasCostDetailEditorOption
if err := rows.Scan(&item.NStokID, &item.SKodu, &item.SAciklama, &item.SModel, &item.SBirim); err != nil {
scanErrors += 1
logger.Warn("item scan error", "scan_index", len(list)+scanErrors, "err", err)
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] item scan error scan_index=%d err=%v", len(list)+scanErrors, err)
continue
}
item.Kind = "item"
item.Value = item.SKodu
item.Label = strings.TrimSpace(item.SKodu + " - " + item.SAciklama)
list = append(list, item)
}
if err := rows.Err(); err != nil {
logger.Error("item rows error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] item rows error search=%q limit=%d err=%v", search, limit, err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "kind", "item", "row_count", len(list), "scan_errors", scanErrors)
log.Printf("[ProductionHasCostDetailEditorOptions] item done search=%q limit=%d row_count=%d scan_errors=%d", search, limit, len(list), scanErrors)
_ = json.NewEncoder(w).Encode(list)
return
case "color":
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
modelCode := strings.TrimSpace(r.URL.Query().Get("model_code"))
if modelCode == "" {
_ = json.NewEncoder(w).Encode([]models.ProductionHasCostDetailEditorOption{})
return
}
rows, err := queries.GetProductionHasCostDetailColorOptions(ctx, uretimDB, modelCode, search, limit)
if err != nil {
logger.Error("color query error", "model_code", modelCode, "err", err)
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] color query error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
defer rows.Close()
list := make([]models.ProductionHasCostDetailEditorOption, 0, limit)
for rows.Next() {
var item models.ProductionHasCostDetailEditorOption
if err := rows.Scan(&item.ColorCode, &item.ColorDescription); err != nil {
logger.Warn("color scan error", "model_code", modelCode, "err", err)
log.Printf("⚠️ [ProductionHasCostDetailEditorOptions] color scan error: %v", err)
continue
}
item.Kind = "color"
item.Value = item.ColorCode
item.Label = strings.TrimSpace(item.ColorCode + " - " + item.ColorDescription)
list = append(list, item)
}
if err := rows.Err(); err != nil {
logger.Error("color rows error", "model_code", modelCode, "err", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "kind", "color", "model_code", modelCode, "row_count", len(list))
_ = json.NewEncoder(w).Encode(list)
return
}
logger.Warn("request invalid", "reason", "invalid kind")
http.Error(w, "kind hammadde, item veya color olmali", http.StatusBadRequest)
}
// GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates
func GetProductionHasCostDetailExchangeRatesHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
mssqlDB := db.GetDB()
if mssqlDB == nil {
http.Error(w, "MSSQL veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
logger := utils.SlogFromContext(ctx).With("handler", "production-product-costing.exchange-rates")
rawCostDate := strings.TrimSpace(r.URL.Query().Get("maliyet_tarihi"))
costDate := ""
if rawCostDate != "" {
parsedDate, err := time.Parse("2006-01-02", rawCostDate)
if err != nil {
logger.Warn("request invalid", "reason", "invalid maliyet_tarihi", "maliyet_tarihi", rawCostDate)
http.Error(w, "maliyet_tarihi YYYY-MM-DD formatinda olmali", http.StatusBadRequest)
return
}
costDate = parsedDate.Format("2006-01-02")
}
logger.Info("request start", "maliyet_tarihi", costDate)
log.Printf("[ProductionHasCostDetailExchangeRates] start maliyet_tarihi=%s", costDate)
row, err := queries.GetProductionHasCostDetailExchangeRatesByDate(ctx, mssqlDB, costDate)
if err != nil {
logger.Error("query prepare error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailExchangeRates] query prepare error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
item := models.ProductionHasCostDetailExchangeRates{
TRYRate: 1,
}
if err := row.Scan(
&item.RateDate,
&item.USDRate,
&item.EURRate,
&item.GBPRate,
); err != nil {
if err == sql.ErrNoRows {
item.RateDate = costDate
logger.Info("request done", "rate_date", item.RateDate, "fallback", true)
_ = json.NewEncoder(w).Encode(item)
return
}
log.Printf("⚠️ [ProductionHasCostDetailExchangeRates] scan error: %v", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "rate_date", item.RateDate, "usd_rate", item.USDRate, "eur_rate", item.EURRate, "gbp_rate", item.GBPRate)
log.Printf("[ProductionHasCostDetailExchangeRates] done maliyet_tarihi=%s rate_date=%s usd=%.4f eur=%.4f", costDate, item.RateDate, item.USDRate, item.EURRate)
_ = json.NewEncoder(w).Encode(item)
}
// POST /api/pricing/production-product-costing/has-cost-detail-bulk-prices
func PostProductionHasCostDetailBulkPricesHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
mssqlDB := db.GetDB()
if mssqlDB == nil {
http.Error(w, "MSSQL veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
logger := utils.SlogFromContext(ctx).With("handler", "production-product-costing.bulk-prices")
var req models.ProductionHasCostDetailBulkPriceRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logger.Warn("request invalid", "reason", "invalid request body", "err", err)
http.Error(w, "Gecersiz istek govdesi", http.StatusBadRequest)
return
}
costDate := strings.TrimSpace(req.MaliyetTarihi)
itemsCount := len(req.Items)
responseChan := make(chan *models.ProductionHasCostDetailBulkPriceRow, itemsCount)
logger.Info("request start",
"n_onml_no", strings.TrimSpace(req.NOnMLNo),
"urun_kodu", strings.TrimSpace(req.UrunKodu),
"maliyet_tarihi", costDate,
"item_count", itemsCount,
)
log.Printf("[ProductionHasCostDetailBulkPrices] start n_onml_no=%s urun_kodu=%s maliyet_tarihi=%s item_count=%d", strings.TrimSpace(req.NOnMLNo), strings.TrimSpace(req.UrunKodu), costDate, itemsCount)
for _, item := range req.Items {
go func(item models.ProductionHasCostDetailPriceLookupItem) {
sKodu := normalizeLookupValue(item.SKodu)
if sKodu == "" {
responseChan <- nil
return
}
colorCode := firstNonEmptyString(
normalizeLookupValue(item.ColorCode),
normalizeLookupValue(item.SRenk),
)
itemDim1Code := firstNonEmptyString(
normalizeLookupValue(item.ItemDim1Code),
)
row, err := queries.GetProductionHasCostLatestPurchasePriceForItem(
ctx,
mssqlDB,
sKodu,
colorCode,
itemDim1Code,
costDate,
)
if err != nil {
logger.Warn("item lookup error", "s_kodu", sKodu, "color_code", colorCode, "item_dim1_code", itemDim1Code, "err", err)
responseChan <- nil
return
}
var result models.ProductionHasCostDetailBulkPriceRow
if err := row.Scan(
&result.PriceType,
&result.Tarih,
&result.FaturaKodu,
&result.MasrafKodu,
&result.MasrafDetay,
&result.ColorCode,
&result.ColorDescription,
&result.ItemDim1Code,
&result.ItemDim1Description,
&result.FiyatGirilen,
&result.FiyatDoviz,
); err != nil {
logger.Warn("item scan error", "s_kodu", sKodu, "color_code", colorCode, "item_dim1_code", itemDim1Code, "err", err)
responseChan <- nil
return
}
result.RowKey = strings.TrimSpace(item.RowKey)
result.NOnMLDetNo = strings.TrimSpace(item.NOnMLDetNo)
result.NHammaddeTuruNo = strings.TrimSpace(item.NHammaddeTuruNo)
result.SKodu = sKodu
if strings.TrimSpace(result.ColorCode) == "" {
result.ColorCode = colorCode
}
if strings.TrimSpace(result.ItemDim1Code) == "" {
result.ItemDim1Code = itemDim1Code
}
responseChan <- &result
}(item)
}
response := make([]models.ProductionHasCostDetailBulkPriceRow, 0, itemsCount)
for i := 0; i < itemsCount; i++ {
res := <-responseChan
if res != nil {
response = append(response, *res)
}
}
logger.Info("request done", "item_count", itemsCount, "matched_count", len(response))
log.Printf("[ProductionHasCostDetailBulkPrices] done item_count=%d matched=%d", itemsCount, len(response))
_ = json.NewEncoder(w).Encode(map[string]any{
"items": response,
})
}
// GET /api/pricing/production-product-costing/has-cost-detail-line-history
func GetProductionHasCostDetailLineHistoryHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
mssqlDB := db.GetDB()
if uretimDB == nil && mssqlDB == nil {
http.Error(w, "Veritabani baglantilari aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
logger := utils.SlogFromContext(ctx).With("handler", "production-product-costing.line-history")
rawOnMLNo := strings.TrimSpace(r.URL.Query().Get("n_onml_no"))
currentOnMLNo, _ := strconv.Atoi(rawOnMLNo)
nHammaddeTuruNo := strings.TrimSpace(r.URL.Query().Get("n_hammadde_turu_no"))
sKodu := normalizeLookupValue(r.URL.Query().Get("s_kodu"))
colorCode := firstNonEmptyString(
normalizeLookupValue(r.URL.Query().Get("color_code")),
normalizeLookupValue(r.URL.Query().Get("s_renk")),
)
costDate := strings.TrimSpace(r.URL.Query().Get("maliyet_tarihi"))
if sKodu == "" {
logger.Warn("request invalid", "reason", "missing s_kodu")
http.Error(w, "s_kodu zorunlu", http.StatusBadRequest)
return
}
logger.Info("request start", "n_onml_no", currentOnMLNo, "n_hammadde_turu_no", nHammaddeTuruNo, "s_kodu", sKodu, "color_code", colorCode, "maliyet_tarihi", costDate)
log.Printf("[ProductionHasCostDetailLineHistory] start n_onml_no=%d n_hammadde_turu_no=%s s_kodu=%s color=%s maliyet_tarihi=%s", currentOnMLNo, nHammaddeTuruNo, sKodu, colorCode, costDate)
const LINE_HISTORY_ROW_LIMIT = 500
response := models.ProductionHasCostDetailLineHistoryResponse{
PurchaseRows: make([]models.ProductionHasCostDetailPurchaseHistoryRow, 0, LINE_HISTORY_ROW_LIMIT),
RecipeRows: make([]models.ProductionHasCostDetailRecipeHistoryRow, 0, LINE_HISTORY_ROW_LIMIT),
}
allowLegacyAutoFallback := true
if mssqlDB != nil {
rows, err := queries.GetProductionHasCostPurchaseHistoryByExpenseCode(
ctx,
mssqlDB,
sKodu,
costDate,
LINE_HISTORY_ROW_LIMIT,
)
if err != nil {
logger.Warn("purchase query error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] purchase query error: %v", err)
} else {
defer rows.Close()
for rows.Next() {
var item models.ProductionHasCostDetailPurchaseHistoryRow
if err := rows.Scan(
&item.SourceType,
&item.PriceType,
&item.Tarih,
&item.FaturaKodu,
&item.FirmaKodu,
&item.FirmaAciklama,
&item.MasrafKodu,
&item.MasrafDetay,
&item.ColorCode,
&item.ColorDescription,
&item.ItemDim1Code,
&item.ItemDim1Description,
&item.Miktar,
&item.BIRIM,
&item.EvrakFiyat,
&item.EvrakTutar,
&item.EvrakDoviz,
); err != nil {
logger.Warn("purchase scan error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] purchase scan error: %v", err)
continue
}
response.PurchaseRows = append(response.PurchaseRows, item)
}
if err := rows.Err(); err != nil {
logger.Warn("purchase rows error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] purchase rows error: %v", err)
}
}
}
if allowLegacyAutoFallback && mssqlDB != nil && len(response.PurchaseRows) == 0 {
similarPrefix := queries.BuildProductionHasCostSimilarCodePrefix(sKodu)
if similarPrefix != "" {
logger.Info("purchase fallback start", "s_kodu", sKodu, "similar_prefix", similarPrefix, "maliyet_tarihi", costDate)
rows, err := queries.GetProductionHasCostPurchaseHistoryByCodePrefix(
ctx,
mssqlDB,
similarPrefix,
costDate,
LINE_HISTORY_ROW_LIMIT,
)
if err != nil {
logger.Warn("purchase fallback query error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] purchase fallback query error: %v", err)
} else {
defer rows.Close()
for rows.Next() {
var item models.ProductionHasCostDetailPurchaseHistoryRow
if err := rows.Scan(
&item.SourceType,
&item.PriceType,
&item.Tarih,
&item.FaturaKodu,
&item.FirmaKodu,
&item.FirmaAciklama,
&item.MasrafKodu,
&item.MasrafDetay,
&item.ColorCode,
&item.ColorDescription,
&item.ItemDim1Code,
&item.ItemDim1Description,
&item.Miktar,
&item.BIRIM,
&item.EvrakFiyat,
&item.EvrakTutar,
&item.EvrakDoviz,
); err != nil {
logger.Warn("purchase fallback scan error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] purchase fallback scan error: %v", err)
continue
}
response.PurchaseRows = append(response.PurchaseRows, item)
}
if err := rows.Err(); err != nil {
logger.Warn("purchase fallback rows error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] purchase fallback rows error: %v", err)
}
}
}
}
if uretimDB != nil {
rows, err := queries.GetProductionHasCostRecipeHistoryByExpenseCode(
ctx,
uretimDB,
currentOnMLNo,
sKodu,
colorCode,
costDate,
LINE_HISTORY_ROW_LIMIT,
)
if err != nil {
logger.Warn("recipe query error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] recipe query error: %v", err)
} else {
defer rows.Close()
for rows.Next() {
var item models.ProductionHasCostDetailRecipeHistoryRow
if err := rows.Scan(
&item.SourceType,
&item.PriceType,
&item.DteIslemTarihi,
&item.NOnMLNo,
&item.FirmaKodu,
&item.FirmaAciklama,
&item.SKodu,
&item.SAciklama,
&item.SRenk,
&item.LMiktar,
&item.SBirim,
&item.LDovizFiyati,
&item.LDovizTutari,
&item.USD,
&item.DUMMY,
); err != nil {
logger.Warn("recipe scan error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] recipe scan error: %v", err)
continue
}
response.RecipeRows = append(response.RecipeRows, item)
}
if err := rows.Err(); err != nil {
logger.Warn("recipe rows error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] recipe rows error: %v", err)
}
}
}
if allowLegacyAutoFallback && uretimDB != nil && len(response.RecipeRows) == 0 {
similarPrefix := queries.BuildProductionHasCostSimilarCodePrefix(sKodu)
if similarPrefix != "" {
logger.Info("recipe fallback prefix start", "s_kodu", sKodu, "similar_prefix", similarPrefix, "maliyet_tarihi", costDate)
rows, err := queries.GetProductionHasCostOnMLHistoryByCodePrefix(
ctx,
uretimDB,
similarPrefix,
costDate,
LINE_HISTORY_ROW_LIMIT,
)
if err != nil {
logger.Warn("recipe fallback prefix query error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] recipe fallback prefix query error: %v", err)
} else {
defer rows.Close()
for rows.Next() {
var item models.ProductionHasCostDetailRecipeHistoryRow
if err := rows.Scan(
&item.SourceType,
&item.PriceType,
&item.DteIslemTarihi,
&item.NOnMLNo,
&item.FirmaKodu,
&item.FirmaAciklama,
&item.SKodu,
&item.SAciklama,
&item.SRenk,
&item.LMiktar,
&item.SBirim,
&item.LDovizFiyati,
&item.LDovizTutari,
&item.USD,
&item.DUMMY,
); err != nil {
logger.Warn("recipe fallback prefix scan error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] recipe fallback prefix scan error: %v", err)
continue
}
response.RecipeRows = append(response.RecipeRows, item)
}
if err := rows.Err(); err != nil {
logger.Warn("recipe fallback prefix rows error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] recipe fallback prefix rows error: %v", err)
}
}
}
}
if allowLegacyAutoFallback && uretimDB != nil && len(response.RecipeRows) == 0 && nHammaddeTuruNo != "" {
logger.Info("recipe fallback hammadde-turu start", "n_hammadde_turu_no", nHammaddeTuruNo, "maliyet_tarihi", costDate)
rows, err := queries.GetProductionHasCostOnMLHistoryByHammaddeTuruNo(
ctx,
uretimDB,
nHammaddeTuruNo,
costDate,
LINE_HISTORY_ROW_LIMIT,
)
if err != nil {
logger.Warn("recipe fallback hammadde-turu query error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] recipe fallback hammadde-turu query error: %v", err)
} else {
defer rows.Close()
for rows.Next() {
var item models.ProductionHasCostDetailRecipeHistoryRow
if err := rows.Scan(
&item.SourceType,
&item.PriceType,
&item.DteIslemTarihi,
&item.NOnMLNo,
&item.FirmaKodu,
&item.FirmaAciklama,
&item.SKodu,
&item.SAciklama,
&item.SRenk,
&item.LMiktar,
&item.SBirim,
&item.LDovizFiyati,
&item.LDovizTutari,
&item.USD,
&item.DUMMY,
); err != nil {
logger.Warn("recipe fallback hammadde-turu scan error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] recipe fallback hammadde-turu scan error: %v", err)
continue
}
response.RecipeRows = append(response.RecipeRows, item)
}
if err := rows.Err(); err != nil {
logger.Warn("recipe fallback hammadde-turu rows error", "err", err)
log.Printf("⚠️ [ProductionHasCostDetailLineHistory] recipe fallback hammadde-turu rows error: %v", err)
}
}
}
logger.Info("request done", "s_kodu", sKodu, "purchase_count", len(response.PurchaseRows), "recipe_count", len(response.RecipeRows))
log.Printf("[ProductionHasCostDetailLineHistory] done s_kodu=%s purchase_rows=%d recipe_rows=%d", sKodu, len(response.PurchaseRows), len(response.RecipeRows))
_ = json.NewEncoder(w).Encode(response)
}
// GET /api/pricing/production-product-costing/has-cost-detail-similar-history
func GetProductionHasCostDetailSimilarHistoryHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
mssqlDB := db.GetDB()
uretimDB := db.GetUretimDB()
if mssqlDB == nil || uretimDB == nil {
http.Error(w, "Veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
logger := utils.SlogFromContext(ctx).With("handler", "production-product-costing.similar-history")
q := r.URL.Query()
nHammaddeTuruNo := strings.TrimSpace(q.Get("n_hammadde_turu_no"))
sKodu := normalizeLookupValue(q.Get("s_kodu"))
costDate := strings.TrimSpace(q.Get("maliyet_tarihi"))
limit := parsePositiveIntOrDefault(q.Get("limit"), 500)
searchMode := strings.ToLower(strings.TrimSpace(q.Get("search_mode")))
if searchMode == "" || searchMode == "exact" {
searchMode = "prefix"
}
similarPrefix := queries.BuildProductionHasCostSimilarCodePrefix(sKodu)
if nHammaddeTuruNo == "" && sKodu == "" {
http.Error(w, "n_hammadde_turu_no veya s_kodu parametresi zorunludur", http.StatusBadRequest)
return
}
logger.Info("request start", "search_mode", searchMode, "n_hammadde_turu_no", nHammaddeTuruNo, "s_kodu", sKodu, "similar_prefix", similarPrefix, "maliyet_tarihi", costDate, "limit", limit)
response := models.ProductionHasCostDetailLineHistoryResponse{
PurchaseRows: make([]models.ProductionHasCostDetailPurchaseHistoryRow, 0, limit),
RecipeRows: make([]models.ProductionHasCostDetailRecipeHistoryRow, 0, limit),
}
purchaseMatchStage := searchMode
recipeMatchStage := searchMode
allowRecipeAutoFallback := false
if searchMode == "alternative" {
purchaseMatchStage = "skipped"
if nHammaddeTuruNo != "" && uretimDB != nil {
rows, err := queries.GetProductionHasCostOnMLHistoryByHammaddeTuruNo(ctx, uretimDB, nHammaddeTuruNo, costDate, limit)
if err != nil {
logger.Warn("alternative onml query error", "err", err)
http.Error(w, "Sorgu calistirilirken hata olustu", http.StatusInternalServerError)
return
}
defer rows.Close()
for rows.Next() {
var item models.ProductionHasCostDetailRecipeHistoryRow
if err := rows.Scan(
&item.SourceType,
&item.PriceType,
&item.DteIslemTarihi,
&item.NOnMLNo,
&item.FirmaKodu,
&item.FirmaAciklama,
&item.SKodu,
&item.SAciklama,
&item.SRenk,
&item.LMiktar,
&item.SBirim,
&item.LDovizFiyati,
&item.LDovizTutari,
&item.USD,
&item.DUMMY,
); err != nil {
logger.Warn("alternative onml scan error", "err", err)
continue
}
response.RecipeRows = append(response.RecipeRows, item)
}
if err := rows.Err(); err != nil {
logger.Warn("alternative onml rows error", "err", err)
}
}
if len(response.PurchaseRows) == 0 {
purchaseMatchStage = "empty"
}
if len(response.RecipeRows) == 0 {
recipeMatchStage = "empty"
}
logger.Info("request done",
"search_mode", searchMode,
"purchase_match_stage", purchaseMatchStage,
"recipe_match_stage", recipeMatchStage,
"similar_prefix", similarPrefix,
"purchase_count", len(response.PurchaseRows),
"recipe_count", len(response.RecipeRows),
)
_ = json.NewEncoder(w).Encode(map[string]any{
"purchaseRows": response.PurchaseRows,
"recipeRows": response.RecipeRows,
"purchase_match_stage": purchaseMatchStage,
"recipe_match_stage": recipeMatchStage,
"similar_code_prefix": similarPrefix,
"search_mode": searchMode,
})
return
}
if similarPrefix != "" {
if mssqlDB != nil {
rows, err := queries.GetProductionHasCostPurchaseHistoryByCodePrefix(ctx, mssqlDB, similarPrefix, costDate, limit)
if err != nil {
logger.Warn("prefix purchase query error", "err", err)
} else {
defer rows.Close()
for rows.Next() {
var item models.ProductionHasCostDetailPurchaseHistoryRow
if err := rows.Scan(
&item.SourceType,
&item.PriceType,
&item.Tarih,
&item.FaturaKodu,
&item.FirmaKodu,
&item.FirmaAciklama,
&item.MasrafKodu,
&item.MasrafDetay,
&item.ColorCode,
&item.ColorDescription,
&item.ItemDim1Code,
&item.ItemDim1Description,
&item.Miktar,
&item.BIRIM,
&item.EvrakFiyat,
&item.EvrakTutar,
&item.EvrakDoviz,
); err != nil {
logger.Warn("prefix purchase scan error", "err", err)
continue
}
response.PurchaseRows = append(response.PurchaseRows, item)
}
if err := rows.Err(); err != nil {
logger.Warn("prefix purchase rows error", "err", err)
}
}
}
if uretimDB != nil {
rows, err := queries.GetProductionHasCostOnMLHistoryByCodePrefix(ctx, uretimDB, similarPrefix, costDate, limit)
if err != nil {
logger.Warn("prefix onml query error", "err", err)
} else {
defer rows.Close()
for rows.Next() {
var item models.ProductionHasCostDetailRecipeHistoryRow
if err := rows.Scan(
&item.SourceType,
&item.PriceType,
&item.DteIslemTarihi,
&item.NOnMLNo,
&item.FirmaKodu,
&item.FirmaAciklama,
&item.SKodu,
&item.SAciklama,
&item.SRenk,
&item.LMiktar,
&item.SBirim,
&item.LDovizFiyati,
&item.LDovizTutari,
&item.USD,
&item.DUMMY,
); err != nil {
logger.Warn("prefix onml scan error", "err", err)
continue
}
response.RecipeRows = append(response.RecipeRows, item)
}
if err := rows.Err(); err != nil {
logger.Warn("prefix onml rows error", "err", err)
}
}
}
}
if allowRecipeAutoFallback && len(response.RecipeRows) == 0 && nHammaddeTuruNo != "" && uretimDB != nil {
recipeMatchStage = "hammadde-turu-fallback"
rows, err := queries.GetProductionHasCostOnMLHistoryByHammaddeTuruNo(ctx, uretimDB, nHammaddeTuruNo, costDate, limit)
if err != nil {
logger.Warn("fallback onml query error", "err", err)
http.Error(w, "Sorgu calistirilirken hata olustu", http.StatusInternalServerError)
return
}
defer rows.Close()
for rows.Next() {
var item models.ProductionHasCostDetailRecipeHistoryRow
if err := rows.Scan(
&item.SourceType,
&item.PriceType,
&item.DteIslemTarihi,
&item.NOnMLNo,
&item.FirmaKodu,
&item.FirmaAciklama,
&item.SKodu,
&item.SAciklama,
&item.SRenk,
&item.LMiktar,
&item.SBirim,
&item.LDovizFiyati,
&item.LDovizTutari,
&item.USD,
&item.DUMMY,
); err != nil {
logger.Warn("fallback onml scan error", "err", err)
continue
}
response.RecipeRows = append(response.RecipeRows, item)
}
if err := rows.Err(); err != nil {
logger.Warn("fallback onml rows error", "err", err)
}
}
if len(response.PurchaseRows) == 0 {
purchaseMatchStage = "empty"
}
if len(response.RecipeRows) == 0 {
recipeMatchStage = "empty"
}
logger.Info("request done",
"search_mode", searchMode,
"purchase_match_stage", purchaseMatchStage,
"recipe_match_stage", recipeMatchStage,
"similar_prefix", similarPrefix,
"purchase_count", len(response.PurchaseRows),
"recipe_count", len(response.RecipeRows),
)
_ = json.NewEncoder(w).Encode(map[string]any{
"purchaseRows": response.PurchaseRows,
"recipeRows": response.RecipeRows,
"purchase_match_stage": purchaseMatchStage,
"recipe_match_stage": recipeMatchStage,
"similar_code_prefix": similarPrefix,
"search_mode": searchMode,
})
}
func parsePositiveIntOrDefault(raw string, fallback int) int {
v, err := strconv.Atoi(strings.TrimSpace(raw))
if err != nil || v < 0 {
return fallback
}
return v
}
func normalizeLookupValue(raw string) string {
return strings.ToUpper(strings.TrimSpace(raw))
}
func firstNonEmptyString(values ...string) string {
for _, value := range values {
value = strings.TrimSpace(value)
if value != "" {
return value
}
}
return ""
}
// ============================================================
// MT BOLUM MAPPING (URETIM DB)
// ============================================================
// GET /api/pricing/production-product-costing/options/urun-ana-grup
func GetProductionProductCostingUrunAnaGrupOptionsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
mssqlDB := db.GetDB()
if mssqlDB == nil {
http.Error(w, "MSSQL veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
search := strings.TrimSpace(r.URL.Query().Get("search"))
limit := parsePositiveIntOrDefault(r.URL.Query().Get("limit"), 50)
if limit > 500 {
limit = 500
}
logger := utils.SlogFromContext(ctx).With(
"handler", "production-product-costing.options.urun-ana-grup",
"search", search,
"limit", limit,
)
logger.Info("request start")
rows, err := queries.GetProductionProductCostingAnaGrupOptions(ctx, mssqlDB, search, limit)
if err != nil {
logger.Error("query error", "err", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
defer rows.Close()
out := make([]models.ProductionProductCostingLookupOption, 0, limit)
for rows.Next() {
var v string
if err := rows.Scan(&v); err != nil {
logger.Warn("scan error", "err", err)
continue
}
v = strings.TrimSpace(v)
if v == "" {
continue
}
out = append(out, models.ProductionProductCostingLookupOption{Value: v, Label: v})
}
if err := rows.Err(); err != nil {
logger.Error("rows error", "err", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "row_count", len(out))
_ = json.NewEncoder(w).Encode(out)
}
// GET /api/pricing/production-product-costing/options/urun-alt-grup
func GetProductionProductCostingUrunAltGrupOptionsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
mssqlDB := db.GetDB()
if mssqlDB == nil {
http.Error(w, "MSSQL veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
urunAnaGrubu := strings.TrimSpace(r.URL.Query().Get("urun_ana_grubu"))
search := strings.TrimSpace(r.URL.Query().Get("search"))
limit := parsePositiveIntOrDefault(r.URL.Query().Get("limit"), 50)
if limit > 500 {
limit = 500
}
logger := utils.SlogFromContext(ctx).With(
"handler", "production-product-costing.options.urun-alt-grup",
"urun_ana_grubu", urunAnaGrubu,
"search", search,
"limit", limit,
)
logger.Info("request start")
rows, err := queries.GetProductionProductCostingAltGrupOptions(ctx, mssqlDB, urunAnaGrubu, search, limit)
if err != nil {
logger.Error("query error", "err", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
defer rows.Close()
out := make([]models.ProductionProductCostingLookupOption, 0, limit)
for rows.Next() {
var v string
if err := rows.Scan(&v); err != nil {
logger.Warn("scan error", "err", err)
continue
}
v = strings.TrimSpace(v)
if v == "" {
continue
}
out = append(out, models.ProductionProductCostingLookupOption{Value: v, Label: v})
}
if err := rows.Err(); err != nil {
logger.Error("rows error", "err", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "row_count", len(out))
_ = json.NewEncoder(w).Encode(out)
}
// GET /api/pricing/production-product-costing/options/urun-ana-alt-combos
func GetProductionProductCostingUrunAnaAltCombosHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
mssqlDB := db.GetDB()
if mssqlDB == nil {
http.Error(w, "MSSQL veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
search := strings.TrimSpace(r.URL.Query().Get("search"))
limit := parsePositiveIntOrDefault(r.URL.Query().Get("limit"), 2000)
if limit > 5000 {
limit = 5000
}
logger := utils.SlogFromContext(ctx).With(
"handler", "production-product-costing.options.urun-ana-alt-combos",
"search", search,
"limit", limit,
)
logger.Info("request start")
rows, err := queries.GetProductionProductCostingAnaAltComboRows(ctx, mssqlDB, search, limit)
if err != nil {
// Keep the response generic, but log the underlying SQL driver error for diagnostics.
logger.Error("query error", "err", err, "search", search, "limit", limit, "trace_id", traceID)
log.Printf("❌ [ProductionProductCostingAnaAltCombos] query error trace_id=%s search=%q limit=%d err=%v", traceID, search, limit, err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
defer rows.Close()
out := make([]models.ProductionProductCostingAnaAltComboRow, 0, 1024)
for rows.Next() {
var item models.ProductionProductCostingAnaAltComboRow
if err := rows.Scan(&item.UrunIlkGrubu, &item.UrunAnaGrubu, &item.UrunAltGrubu); err != nil {
logger.Warn("scan error", "err", err)
continue
}
item.UrunIlkGrubu = strings.TrimSpace(item.UrunIlkGrubu)
item.UrunAnaGrubu = strings.TrimSpace(item.UrunAnaGrubu)
item.UrunAltGrubu = strings.TrimSpace(item.UrunAltGrubu)
if item.UrunIlkGrubu == "" || item.UrunAnaGrubu == "" || item.UrunAltGrubu == "" {
continue
}
out = append(out, item)
}
if err := rows.Err(); err != nil {
logger.Error("rows error", "err", err, "trace_id", traceID)
log.Printf("⚠️ [ProductionProductCostingAnaAltCombos] rows error trace_id=%s err=%v", traceID, err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "row_count", len(out))
_ = json.NewEncoder(w).Encode(out)
}
// GET /api/pricing/production-product-costing/options/mtbolum
func GetProductionProductCostingMTBolumOptionsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
search := strings.TrimSpace(r.URL.Query().Get("search"))
limit := parsePositiveIntOrDefault(r.URL.Query().Get("limit"), 50)
if limit > 500 {
limit = 500
}
logger := utils.SlogFromContext(ctx).With(
"handler", "production-product-costing.options.mtbolum",
"search", search,
"limit", limit,
)
logger.Info("request start")
rows, err := queries.GetProductionProductCostingMTBolumOptions(ctx, uretimDB, search, limit)
if err != nil {
logger.Error("query error", "err", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
defer rows.Close()
out := make([]models.ProductionProductCostingLookupOption, 0, limit)
for rows.Next() {
var id int
var name string
if err := rows.Scan(&id, &name); err != nil {
logger.Warn("scan error", "err", err)
continue
}
label := strings.TrimSpace(strconv.Itoa(id) + " - " + strings.TrimSpace(name))
out = append(out, models.ProductionProductCostingLookupOption{
Value: strconv.Itoa(id),
Label: label,
})
}
if err := rows.Err(); err != nil {
logger.Error("rows error", "err", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "row_count", len(out))
_ = json.NewEncoder(w).Encode(out)
}
// GET /api/pricing/production-product-costing/maliyet-parca-eslestirme
func GetProductionProductCostingParcaMappingsHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
urunIlkGrubu := strings.TrimSpace(r.URL.Query().Get("urun_ilk_grubu"))
urunAnaGrubu := strings.TrimSpace(r.URL.Query().Get("urun_ana_grubu"))
urunAltGrubu := strings.TrimSpace(r.URL.Query().Get("urun_alt_grubu"))
nUrtMTBolumID := parsePositiveIntOrDefault(r.URL.Query().Get("n_urt_mt_bolum_id"), 0)
rawOnlyActive := strings.TrimSpace(r.URL.Query().Get("only_active"))
var onlyActive *bool = nil
if rawOnlyActive != "" {
v := rawOnlyActive == "1" || strings.EqualFold(rawOnlyActive, "true")
onlyActive = &v
}
logger := utils.SlogFromContext(ctx).With(
"handler", "production-product-costing.maliyet-parca-eslestirme.list",
"urun_ilk_grubu", urunIlkGrubu,
"urun_ana_grubu", urunAnaGrubu,
"urun_alt_grubu", urunAltGrubu,
"n_urt_mt_bolum_id", nUrtMTBolumID,
"only_active", rawOnlyActive,
)
logger.Info("request start")
rows, err := queries.ListProductionProductCostingParcaMappings(ctx, uretimDB, urunIlkGrubu, urunAnaGrubu, urunAltGrubu, nUrtMTBolumID, onlyActive)
if err != nil {
logger.Error("query error", "err", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
defer rows.Close()
out := make([]models.ProductionProductCostingParcaMappingRow, 0, 200)
for rows.Next() {
var row models.ProductionProductCostingParcaMappingRow
var bAktif sql.NullBool
var hammaddeCsv sql.NullString
if err := rows.Scan(
&row.ID,
&row.UrunIlkGrubu,
&row.UrunAnaGrubu,
&row.UrunAltGrubu,
&row.NUrtMTBolumID,
&row.ParcaBolumAdi,
&hammaddeCsv,
&bAktif,
&row.DteIslem,
&row.SKullaniciAdi,
); err != nil {
logger.Warn("scan error", "err", err)
continue
}
row.BAktif = bAktif.Valid && bAktif.Bool
row.NHammaddeTurleri = make([]string, 0, 8)
if hammaddeCsv.Valid {
for _, part := range strings.Split(hammaddeCsv.String, ",") {
part = strings.TrimSpace(part)
if part != "" {
row.NHammaddeTurleri = append(row.NHammaddeTurleri, part)
}
}
}
out = append(out, row)
}
if err := rows.Err(); err != nil {
logger.Error("rows error", "err", err)
http.Error(w, "Veritabani satir hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "row_count", len(out))
_ = json.NewEncoder(w).Encode(out)
}
// POST /api/pricing/production-product-costing/maliyet-parca-eslestirme/upsert
func PostProductionProductCostingParcaMappingUpsertHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
claims, _ := auth.GetClaimsFromContext(r.Context())
user := ""
if claims != nil {
user = strings.TrimSpace(claims.Username)
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
logger := utils.SlogFromContext(ctx).With("handler", "production-product-costing.maliyet-parca-eslestirme.upsert")
logger.Info("request start")
var req models.ProductionProductCostingParcaMappingUpsertRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logger.Warn("invalid json", "err", err)
http.Error(w, "Gecersiz JSON", http.StatusBadRequest)
return
}
req.UrunAnaGrubu = strings.TrimSpace(req.UrunAnaGrubu)
req.UrunAltGrubu = strings.TrimSpace(req.UrunAltGrubu)
req.UrunIlkGrubu = strings.TrimSpace(req.UrunIlkGrubu)
if req.UrunIlkGrubu == "" || req.UrunAnaGrubu == "" || req.UrunAltGrubu == "" || req.NUrtMTBolumID <= 0 {
http.Error(w, "urunIlkGrubu, urunAnaGrubu, urunAltGrubu ve nUrtMTBolumID zorunlu", http.StatusBadRequest)
return
}
id, err := queries.UpsertProductionProductCostingParcaMapping(ctx, uretimDB, req.UrunIlkGrubu, req.UrunAnaGrubu, req.UrunAltGrubu, req.NUrtMTBolumID, req.NHammaddeTurleri, req.BAktif, user)
if err != nil {
logger.Error("exec error", "err", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "id", id, "user", user, "bAktif", req.BAktif)
_ = json.NewEncoder(w).Encode(map[string]any{"ok": true, "id": id})
}
type productionProductCostingSetActiveRequest struct {
ID int `json:"id"`
BAktif bool `json:"bAktif"`
}
// POST /api/pricing/production-product-costing/maliyet-parca-eslestirme/set-active
func PostProductionProductCostingParcaMappingSetActiveHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
claims, _ := auth.GetClaimsFromContext(r.Context())
user := ""
if claims != nil {
user = strings.TrimSpace(claims.Username)
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
logger := utils.SlogFromContext(ctx).With("handler", "production-product-costing.maliyet-parca-eslestirme.set-active")
logger.Info("request start")
var req productionProductCostingSetActiveRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
logger.Warn("invalid json", "err", err)
http.Error(w, "Gecersiz JSON", http.StatusBadRequest)
return
}
if req.ID <= 0 {
http.Error(w, "id zorunlu", http.StatusBadRequest)
return
}
if err := queries.SetProductionProductCostingParcaMappingActive(ctx, uretimDB, req.ID, req.BAktif, user); err != nil {
logger.Error("exec error", "err", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "id", req.ID, "bAktif", req.BAktif, "user", user)
_ = json.NewEncoder(w).Encode(map[string]any{"ok": true})
}
// DELETE /api/pricing/production-product-costing/maliyet-parca-eslestirme?id=123
func DeleteProductionProductCostingParcaMappingHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
uretimDB := db.GetUretimDB()
if uretimDB == nil {
http.Error(w, "URETIM veritabani baglantisi aktif degil", http.StatusServiceUnavailable)
return
}
traceID := utils.TraceIDFromRequest(r)
ctx := utils.ContextWithTraceID(r.Context(), traceID)
logger := utils.SlogFromContext(ctx).With("handler", "production-product-costing.maliyet-parca-eslestirme.delete")
logger.Info("request start")
id := parsePositiveIntOrDefault(r.URL.Query().Get("id"), 0)
if id <= 0 {
http.Error(w, "id zorunlu", http.StatusBadRequest)
return
}
if err := queries.DeleteProductionProductCostingParcaMapping(ctx, uretimDB, id); err != nil {
logger.Error("exec error", "err", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
return
}
logger.Info("request done", "id", id)
_ = json.NewEncoder(w).Encode(map[string]any{"ok": true})
}

1
svc/tmp_backend.err.log Normal file
View File

@@ -0,0 +1 @@
exit status 1

157
svc/tmp_backend.out.log Normal file
View File

@@ -0,0 +1,157 @@
time=2026-05-03T21:39:36.490+03:00 level=INFO msg="backend start" app=bssapp-backend scope=main
time=2026-05-03T21:39:36.508+03:00 level=INFO msg="🔥🔥🔥 BSSAPP BACKEND STARTED — LOGIN ROUTE SHOULD EXIST 🔥🔥🔥" app=bssapp-backend
time=2026-05-03T21:39:36.509+03:00 level=INFO msg="🔐 JWT_SECRET yüklendi" app=bssapp-backend
MSSQL baglantisi basarili (connection timeout=120s, dial timeout=120s)
URETIM MSSQL baglantisi basarili (connection timeout=120s, dial timeout=120s)
time=2026-05-03T21:39:36.926+03:00 level=INFO msg="PostgreSQL bağlantısı başarılı" app=bssapp-backend
time=2026-05-03T21:39:37.222+03:00 level=INFO msg="✅ Admin dept permissions seeded" app=bssapp-backend
time=2026-05-03T21:39:37.223+03:00 level=INFO msg="🟢 auditlog Init called, buffer: 1000" app=bssapp-backend
time=2026-05-03T21:39:37.224+03:00 level=INFO msg="🕵️ AuditLog sistemi başlatıldı (buffer=1000)" app=bssapp-backend
time=2026-05-03T21:39:37.224+03:00 level=INFO msg="🟢 auditlog worker STARTED" app=bssapp-backend
time=2026-05-03T21:39:37.306+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE EXTENSION IF NOT EXISTS pg_trgm\"" app=bssapp-backend
time=2026-05-03T21:39:37.386+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_t_key_lang ON mk_translator (t_key, lang_code)\"" app=bssapp-backend
time=2026-05-03T21:39:37.471+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_status_lang_updated ON mk_translator (status, lang_code...\"" app=bssapp-backend
time=2026-05-03T21:39:37.553+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_manual_status ON mk_translator (is_manual, status)\"" app=bssapp-backend
time=2026-05-03T21:39:37.635+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_source_type_expr ON mk_translator ((COALESCE(NULLIF(pro...\"" app=bssapp-backend
time=2026-05-03T21:39:37.717+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_source_text_trgm ON mk_translator USING gin (source_tex...\"" app=bssapp-backend
time=2026-05-03T21:39:37.799+03:00 level=INFO msg="[TranslationPerf] index_ready sql=\"CREATE INDEX IF NOT EXISTS idx_mk_translator_translated_text_trgm ON mk_translator USING gin (transl...\"" app=bssapp-backend
time=2026-05-03T21:39:37.799+03:00 level=INFO msg="✉️ Graph Mailer hazır (App-only token) | from=baggiss@baggi.com.tr" app=bssapp-backend
time=2026-05-03T21:39:37.799+03:00 level=INFO msg="✉️ Graph Mailer hazır" app=bssapp-backend
📋 [DEBUG] İlk 10 kullanıcı:
- 1 : ctengiz
- 2 : ali.kale
- 5 : mehmet.keçeci
- 6 : mert.keçeci
- 7 : samet.keçeci
- 9 : orhan.caliskan
- 10 : nilgun.sara
- 14 : rustem.kurbanov
- 15 : caner.akyol
- 16 : kemal.matyakupov
time=2026-05-03T21:39:38.702+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/auth/login [auth:login]" app=bssapp-backend
time=2026-05-03T21:39:39.525+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/auth/refresh [auth:refresh]" app=bssapp-backend
time=2026-05-03T21:39:40.343+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/password/forgot [auth:update]" app=bssapp-backend
time=2026-05-03T21:39:41.180+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/password/reset/validate/{token} [auth:view]" app=bssapp-backend
time=2026-05-03T21:39:41.998+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/password/reset [auth:update]" app=bssapp-backend
time=2026-05-03T21:39:42.815+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/password/change [auth:update]" app=bssapp-backend
time=2026-05-03T21:39:43.636+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/activity-logs [system:read]" app=bssapp-backend
time=2026-05-03T21:39:44.451+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/test-mail [system:update]" app=bssapp-backend
time=2026-05-03T21:39:45.268+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/system/market-mail-mappings/lookups [system:update]" app=bssapp-backend
time=2026-05-03T21:39:46.088+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/system/market-mail-mappings [system:update]" app=bssapp-backend
time=2026-05-03T21:39:46.905+03:00 level=INFO msg="✅ Route+Perm registered → PUT /api/system/market-mail-mappings/{marketId} [system:update]" app=bssapp-backend
time=2026-05-03T21:39:47.722+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/language/translations [language:update]" app=bssapp-backend
time=2026-05-03T21:39:48.540+03:00 level=INFO msg="✅ Route+Perm registered → PUT /api/language/translations/{id} [language:update]" app=bssapp-backend
time=2026-05-03T21:39:49.366+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/language/translations/upsert-missing [language:update]" app=bssapp-backend
time=2026-05-03T21:39:50.191+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/language/translations/sync-sources [language:update]" app=bssapp-backend
time=2026-05-03T21:39:51.011+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/language/translations/translate-selected [language:update]" app=bssapp-backend
time=2026-05-03T21:39:51.827+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/language/translations/bulk-approve [language:update]" app=bssapp-backend
time=2026-05-03T21:39:52.647+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/language/translations/bulk-update [language:update]" app=bssapp-backend
time=2026-05-03T21:39:53.473+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/roles/{id}/permissions [system:update]" app=bssapp-backend
time=2026-05-03T21:39:54.310+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/roles/{id}/permissions [system:update]" app=bssapp-backend
time=2026-05-03T21:39:55.165+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/users/{id}/permissions [system:update]" app=bssapp-backend
time=2026-05-03T21:39:56.030+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users/{id}/permissions [system:update]" app=bssapp-backend
time=2026-05-03T21:39:56.877+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/permissions/routes [system:view]" app=bssapp-backend
time=2026-05-03T21:39:57.718+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/permissions/effective [system:view]" app=bssapp-backend
time=2026-05-03T21:39:58.552+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/permissions/matrix [system:view]" app=bssapp-backend
time=2026-05-03T21:39:59.385+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/role-dept-permissions/list [system:update]" app=bssapp-backend
time=2026-05-03T21:40:00.208+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/roles/{roleId}/departments/{deptCode}/permissions [system:update]" app=bssapp-backend
time=2026-05-03T21:40:01.043+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/roles/{roleId}/departments/{deptCode}/permissions [system:update]" app=bssapp-backend
time=2026-05-03T21:40:01.861+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/users/list [user:view]" app=bssapp-backend
time=2026-05-03T21:40:02.685+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users [user:insert]" app=bssapp-backend
time=2026-05-03T21:40:03.509+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/users/{id} [user:update]" app=bssapp-backend
time=2026-05-03T21:40:04.357+03:00 level=INFO msg="✅ Route+Perm registered → PUT /api/users/{id} [user:update]" app=bssapp-backend
time=2026-05-03T21:40:05.218+03:00 level=INFO msg="✅ Route+Perm registered → DELETE /api/users/{id} [user:delete]" app=bssapp-backend
time=2026-05-03T21:40:06.102+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users/{id}/admin-reset-password [user:update]" app=bssapp-backend
time=2026-05-03T21:40:06.946+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users/{id}/send-password-mail [user:update]" app=bssapp-backend
time=2026-05-03T21:40:07.760+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users/create [user:insert]" app=bssapp-backend
time=2026-05-03T21:40:08.577+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/modules [user:view]" app=bssapp-backend
time=2026-05-03T21:40:09.402+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/roles [user:view]" app=bssapp-backend
time=2026-05-03T21:40:10.216+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/departments [user:view]" app=bssapp-backend
time=2026-05-03T21:40:11.051+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/nebim-users [user:view]" app=bssapp-backend
time=2026-05-03T21:40:11.932+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/piyasalar [user:view]" app=bssapp-backend
time=2026-05-03T21:40:12.770+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/users-perm [user:view]" app=bssapp-backend
time=2026-05-03T21:40:13.610+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/roles-perm [user:view]" app=bssapp-backend
time=2026-05-03T21:40:14.445+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/lookups/departments-perm [user:view]" app=bssapp-backend
time=2026-05-03T21:40:15.268+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/accounts [customer:view]" app=bssapp-backend
time=2026-05-03T21:40:16.090+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/customer-list [customer:view]" app=bssapp-backend
time=2026-05-03T21:40:16.921+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/today-currency [finance:view]" app=bssapp-backend
time=2026-05-03T21:40:17.735+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/export-pdf [finance:export]" app=bssapp-backend
time=2026-05-03T21:40:18.573+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/exportstamentheaderreport-pdf [finance:export]" app=bssapp-backend
time=2026-05-03T21:40:19.416+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/customer-balances [finance:view]" app=bssapp-backend
time=2026-05-03T21:40:20.262+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/customer-balances/export-pdf [finance:export]" app=bssapp-backend
time=2026-05-03T21:40:21.096+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/customer-balances/export-excel [finance:export]" app=bssapp-backend
time=2026-05-03T21:40:21.915+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/account-aging-statement [finance:view]" app=bssapp-backend
time=2026-05-03T21:40:22.770+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/account-aging-statement/export-pdf [finance:export]" app=bssapp-backend
time=2026-05-03T21:40:23.607+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/account-aging-statement/export-screen-pdf [finance:export]" app=bssapp-backend
time=2026-05-03T21:40:24.427+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/account-aging-statement/export-excel [finance:export]" app=bssapp-backend
time=2026-05-03T21:40:25.254+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/finance/aged-customer-balance-list [finance:view]" app=bssapp-backend
time=2026-05-03T21:40:26.082+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/statements [finance:view]" app=bssapp-backend
time=2026-05-03T21:40:26.915+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/statements/{id}/details [finance:view]" app=bssapp-backend
time=2026-05-03T21:40:27.733+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/order/create [order:insert]" app=bssapp-backend
time=2026-05-03T21:40:28.560+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/order/update [order:update]" app=bssapp-backend
time=2026-05-03T21:40:29.446+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/order/{id}/bulk-due-date [order:update]" app=bssapp-backend
time=2026-05-03T21:40:30.278+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/order/get/{id} [order:view]" app=bssapp-backend
time=2026-05-03T21:40:31.103+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/list [order:view]" app=bssapp-backend
time=2026-05-03T21:40:31.929+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/production-list [order:update]" app=bssapp-backend
time=2026-05-03T21:40:32.753+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/production-items/cditem-lookups [order:view]" app=bssapp-backend
time=2026-05-03T21:40:33.571+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/production-items/{id} [order:view]" app=bssapp-backend
time=2026-05-03T21:40:34.385+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/orders/production-items/{id}/insert-missing [order:update]" app=bssapp-backend
time=2026-05-03T21:40:35.206+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/orders/production-items/{id}/validate [order:update]" app=bssapp-backend
time=2026-05-03T21:40:36.027+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/orders/production-items/{id}/apply [order:update]" app=bssapp-backend
time=2026-05-03T21:40:36.841+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/close-ready [order:update]" app=bssapp-backend
time=2026-05-03T21:40:37.670+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/orders/bulk-close [order:update]" app=bssapp-backend
time=2026-05-03T21:40:38.506+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orders/export [order:export]" app=bssapp-backend
time=2026-05-03T21:40:39.341+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/order/check/{id} [order:view]" app=bssapp-backend
time=2026-05-03T21:40:40.201+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/order/validate [order:insert]" app=bssapp-backend
time=2026-05-03T21:40:41.036+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/order/pdf/{id} [order:export]" app=bssapp-backend
time=2026-05-03T21:40:41.857+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/order/send-market-mail [order:read]" app=bssapp-backend
time=2026-05-03T21:40:42.673+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/order-inventory [order:view]" app=bssapp-backend
time=2026-05-03T21:40:43.498+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/orderpricelistb2b [order:view]" app=bssapp-backend
time=2026-05-03T21:40:44.313+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/min-price [order:view]" app=bssapp-backend
time=2026-05-03T21:40:45.140+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/products [order:view]" app=bssapp-backend
time=2026-05-03T21:40:45.993+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-detail [order:view]" app=bssapp-backend
time=2026-05-03T21:40:46.836+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-cditem [order:view]" app=bssapp-backend
time=2026-05-03T21:40:47.696+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-colors [order:view]" app=bssapp-backend
time=2026-05-03T21:40:48.557+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-newcolors [order:view]" app=bssapp-backend
time=2026-05-03T21:40:49.393+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-colorsize [order:view]" app=bssapp-backend
time=2026-05-03T21:40:50.212+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-secondcolor [order:view]" app=bssapp-backend
time=2026-05-03T21:40:51.042+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-newsecondcolor [order:view]" app=bssapp-backend
time=2026-05-03T21:40:51.871+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-attributes [order:view]" app=bssapp-backend
time=2026-05-03T21:40:52.704+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-item-attributes [order:view]" app=bssapp-backend
time=2026-05-03T21:40:53.518+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-stock-query [order:view]" app=bssapp-backend
time=2026-05-03T21:40:54.344+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-stock-attribute-options [order:view]" app=bssapp-backend
time=2026-05-03T21:40:55.177+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-stock-query-by-attributes [order:view]" app=bssapp-backend
time=2026-05-03T21:40:56.013+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-images [order:view]" app=bssapp-backend
time=2026-05-03T21:40:56.845+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-images/{id}/content [order:view]" app=bssapp-backend
time=2026-05-03T21:40:57.677+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/product-size-match/rules [order:view]" app=bssapp-backend
time=2026-05-03T21:40:58.502+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/products [order:view]" app=bssapp-backend
time=2026-05-03T21:40:59.343+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/no-cost-products [order:view]" app=bssapp-backend
time=2026-05-03T21:41:00.155+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-products [order:view]" app=bssapp-backend
time=2026-05-03T21:41:00.974+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-history [order:view]" app=bssapp-backend
time=2026-05-03T21:41:01.791+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-detail-groups [order:view]" app=bssapp-backend
time=2026-05-03T21:41:02.612+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-detail-header [order:view]" app=bssapp-backend
time=2026-05-03T21:41:03.482+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/production-types [order:view]" app=bssapp-backend
time=2026-05-03T21:41:04.331+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/detail-editor-options [order:view]" app=bssapp-backend
time=2026-05-03T21:41:05.183+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-detail-exchange-rates [order:view]" app=bssapp-backend
time=2026-05-03T21:41:06.013+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-detail-line-history [order:view]" app=bssapp-backend
time=2026-05-03T21:41:06.839+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/has-cost-detail-similar-history [order:view]" app=bssapp-backend
time=2026-05-03T21:41:07.662+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/pricing/production-product-costing/has-cost-detail-bulk-prices [order:view]" app=bssapp-backend
time=2026-05-03T21:41:08.497+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/options/urun-ana-grup [order:view]" app=bssapp-backend
time=2026-05-03T21:41:09.318+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/options/urun-alt-grup [order:view]" app=bssapp-backend
time=2026-05-03T21:41:10.135+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/options/urun-ana-alt-combos [order:view]" app=bssapp-backend
time=2026-05-03T21:41:10.952+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/options/mtbolum [order:view]" app=bssapp-backend
time=2026-05-03T21:41:11.795+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/pricing/production-product-costing/maliyet-parca-eslestirme [order:view]" app=bssapp-backend
time=2026-05-03T21:41:12.633+03:00 level=INFO msg="✅ Route+Perm registered → DELETE /api/pricing/production-product-costing/maliyet-parca-eslestirme [order:view]" app=bssapp-backend
time=2026-05-03T21:41:13.473+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/pricing/production-product-costing/maliyet-parca-eslestirme/upsert [order:view]" app=bssapp-backend
time=2026-05-03T21:41:14.327+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/pricing/production-product-costing/maliyet-parca-eslestirme/set-active [order:view]" app=bssapp-backend
time=2026-05-03T21:41:15.176+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/roles [user:view]" app=bssapp-backend
time=2026-05-03T21:41:16.018+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/departments [user:view]" app=bssapp-backend
time=2026-05-03T21:41:16.855+03:00 level=INFO msg="✅ Route+Perm registered → GET /api/piyasalar [user:view]" app=bssapp-backend
time=2026-05-03T21:41:17.674+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/roles/{id}/departments [user:update]" app=bssapp-backend
time=2026-05-03T21:41:18.487+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/roles/{id}/piyasalar [user:update]" app=bssapp-backend
time=2026-05-03T21:41:19.308+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/users/{id}/roles [user:update]" app=bssapp-backend
time=2026-05-03T21:41:20.120+03:00 level=INFO msg="✅ Route+Perm registered → POST /api/admin/users/{id}/piyasa-sync [admin:user.update]" app=bssapp-backend
time=2026-05-03T21:41:20.120+03:00 level=INFO msg="🌍 CORS Allowed Origin: http://ss.baggi.com.tr/app" app=bssapp-backend
time=2026-05-03T21:41:20.121+03:00 level=INFO msg="🚀 Server running at: 0.0.0.0:8080" app=bssapp-backend
time=2026-05-03T21:41:20.121+03:00 level=INFO msg="🕓 Translation sync next run at 2026-05-04T04:00:00+03:00 (in 6h18m40s)" app=bssapp-backend
time=2026-05-03T21:41:20.122+03:00 level=INFO msg="listen tcp 0.0.0.0:8080: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted." app=bssapp-backend

78
svc/utils/slog.go Normal file
View File

@@ -0,0 +1,78 @@
package utils
import (
"context"
"log/slog"
"net/http"
"os"
"strings"
)
type traceIDContextKey string
const traceIDKey traceIDContextKey = "trace_id"
func InitSlog() {
level := new(slog.LevelVar)
switch strings.ToLower(strings.TrimSpace(os.Getenv("SLOG_LEVEL"))) {
case "debug":
level.Set(slog.LevelDebug)
case "warn":
level.Set(slog.LevelWarn)
case "error":
level.Set(slog.LevelError)
default:
level.Set(slog.LevelInfo)
}
handler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
Level: level,
AddSource: false,
})
slog.SetDefault(slog.New(handler).With("app", "bssapp-backend"))
}
func TraceIDFromRequest(r *http.Request) string {
if r == nil {
return ""
}
candidates := []string{
strings.TrimSpace(r.Header.Get("X-Trace-ID")),
strings.TrimSpace(r.URL.Query().Get("trace_id")),
strings.TrimSpace(r.Header.Get("X-Request-ID")),
}
for _, candidate := range candidates {
if candidate != "" {
return candidate
}
}
return ""
}
func ContextWithTraceID(ctx context.Context, traceID string) context.Context {
traceID = strings.TrimSpace(traceID)
if ctx == nil || traceID == "" {
return ctx
}
return context.WithValue(ctx, traceIDKey, traceID)
}
func TraceIDFromContext(ctx context.Context) string {
if ctx == nil {
return ""
}
value, _ := ctx.Value(traceIDKey).(string)
return strings.TrimSpace(value)
}
func SlogFromContext(ctx context.Context) *slog.Logger {
traceID := TraceIDFromContext(ctx)
if traceID == "" {
return slog.Default()
}
return slog.Default().With("trace_id", traceID)
}