Files
bssapp/svc/queries/orderproduction_items.go
2026-04-15 15:54:44 +03:00

1695 lines
55 KiB
Go

package queries
import (
"database/sql"
"fmt"
"log"
"sort"
"strconv"
"strings"
"time"
"bssapp-backend/models"
)
// ========================================================
// 📌 GetOrderProductionItems — OrderHeaderID için U ürünleri
// ========================================================
func GetOrderProductionItems(mssql *sql.DB, orderHeaderID string) (*sql.Rows, error) {
return mssql.Query(`
SELECT
CAST(l.OrderHeaderID AS NVARCHAR(50)) AS OrderHeaderID,
CAST(l.OrderLineID AS NVARCHAR(50)) AS OrderLineID,
l.ItemTypeCode AS ItemTypeCode,
ISNULL(l.ItemDim1Code,'') AS OldDim1,
ISNULL(l.ItemDim3Code,'') AS OldDim3,
ISNULL(l.ItemCode,'') AS OldItemCode,
ISNULL(l.ColorCode,'') AS OldColor,
ISNULL((
SELECT TOP 1 LTRIM(RTRIM(cd.ColorDescription))
FROM dbo.cdColorDesc cd WITH (NOLOCK)
WHERE cd.ColorCode = l.ColorCode
AND cd.LangCode = N'TR'
), '') AS OldColorDescription,
ISNULL(l.ItemDim2Code,'') AS OldDim2,
ISNULL(l.LineDescription,'') AS OldDesc,
CAST(ISNULL(l.Qty1, 0) AS FLOAT) AS OldQty,
CAST('' AS NVARCHAR(60)) AS NewItemCode,
CAST('' AS NVARCHAR(30)) AS NewColor,
CAST('' AS NVARCHAR(30)) AS NewDim2,
CAST('' AS NVARCHAR(250)) AS NewDesc,
CONVERT(NVARCHAR(10), l.DeliveryDate, 126) AS OldDueDate,
CONVERT(NVARCHAR(10), l.DeliveryDate, 126) AS NewDueDate,
CAST(0 AS bit) AS IsVariantMissing
FROM dbo.trOrderLine l
WHERE l.OrderHeaderID = @p1
AND ISNULL(l.ItemCode,'') LIKE 'U%'
ORDER BY l.SortOrder, l.OrderLineID
`, orderHeaderID)
}
// ========================================================
// 📌 InsertMissingProductionVariants — eksik prItemVariant ekler
// ========================================================
func InsertMissingProductionVariants(mssql *sql.DB, orderHeaderID string, username string) (int64, error) {
query := `
;WITH Missing AS (
SELECT DISTINCT
l.ItemTypeCode,
l.ItemCode,
l.ColorCode,
l.ItemDim1Code,
l.ItemDim2Code,
l.ItemDim3Code
FROM dbo.trOrderLine l
LEFT JOIN dbo.prItemVariant pv
ON pv.ItemTypeCode = l.ItemTypeCode
AND ISNULL(LTRIM(RTRIM(pv.ItemCode)),'') = ISNULL(LTRIM(RTRIM(l.ItemCode)),'')
AND ISNULL(LTRIM(RTRIM(pv.ColorCode)),'') = ISNULL(LTRIM(RTRIM(l.ColorCode)),'')
AND ISNULL(LTRIM(RTRIM(pv.ItemDim1Code)),'') = ISNULL(LTRIM(RTRIM(l.ItemDim1Code)),'')
AND ISNULL(LTRIM(RTRIM(pv.ItemDim2Code)),'') = ISNULL(LTRIM(RTRIM(l.ItemDim2Code)),'')
AND ISNULL(LTRIM(RTRIM(pv.ItemDim3Code)),'') = ISNULL(LTRIM(RTRIM(l.ItemDim3Code)),'')
WHERE l.OrderHeaderID = @p1
AND ISNULL(l.ItemCode,'') LIKE 'U%'
AND pv.ItemCode IS NULL
)
INSERT INTO dbo.prItemVariant (
ItemTypeCode,
ItemCode,
ColorCode,
ItemDim1Code,
ItemDim2Code,
ItemDim3Code,
IsSalesOrderClosed,
IsPurchaseOrderClosed,
IsLocked,
IsBlocked,
CreatedUserName,
CreatedDate,
LastUpdatedUserName,
LastUpdatedDate,
RowGuid,
UseInternet,
IsStoreOrderClosed
)
SELECT
m.ItemTypeCode,
m.ItemCode,
m.ColorCode,
m.ItemDim1Code,
m.ItemDim2Code,
m.ItemDim3Code,
0,
0,
0,
0,
@p2,
GETDATE(),
@p2,
GETDATE(),
NEWID(),
0,
0
FROM Missing m;
`
res, err := mssql.Exec(query, orderHeaderID, username)
if err != nil {
return 0, err
}
return res.RowsAffected()
}
// ========================================================
// OrderProductionUpdate - variant kontrolu ve guncelleme
// ========================================================
func GetOrderLineDims(mssql *sql.DB, orderHeaderID string, orderLineID string) (int16, string, string, string, error) {
var itemTypeCode int16
var dim1 string
var dim2 string
var dim3 string
err := mssql.QueryRow(`
SELECT
ItemTypeCode,
ISNULL(ItemDim1Code,'') AS ItemDim1Code,
ISNULL(ItemDim2Code,'') AS ItemDim2Code,
ISNULL(ItemDim3Code,'') AS ItemDim3Code
FROM dbo.trOrderLine
WHERE OrderHeaderID = @p1 AND OrderLineID = @p2
`, orderHeaderID, orderLineID).Scan(&itemTypeCode, &dim1, &dim2, &dim3)
return itemTypeCode, dim1, dim2, dim3, err
}
type OrderLineDims struct {
ItemTypeCode int16
ItemDim1Code string
ItemDim2Code string
ItemDim3Code string
}
func GetOrderLineDimsMap(mssql *sql.DB, orderHeaderID string) (map[string]OrderLineDims, error) {
rows, err := mssql.Query(`
SELECT
CAST(OrderLineID AS NVARCHAR(50)) AS OrderLineID,
ItemTypeCode,
ISNULL(ItemDim1Code,'') AS ItemDim1Code,
ISNULL(ItemDim2Code,'') AS ItemDim2Code,
ISNULL(ItemDim3Code,'') AS ItemDim3Code
FROM dbo.trOrderLine WITH(NOLOCK)
WHERE OrderHeaderID = @p1
`, orderHeaderID)
if err != nil {
return nil, err
}
defer rows.Close()
out := make(map[string]OrderLineDims, 128)
for rows.Next() {
var lineID string
var d OrderLineDims
if err := rows.Scan(&lineID, &d.ItemTypeCode, &d.ItemDim1Code, &d.ItemDim2Code, &d.ItemDim3Code); err != nil {
return nil, err
}
out[strings.TrimSpace(lineID)] = d
}
if err := rows.Err(); err != nil {
return nil, err
}
return out, nil
}
func VariantExists(mssql *sql.DB, itemTypeCode int16, itemCode string, colorCode string, dim1 string, dim2 string, dim3 string) (bool, error) {
var exists int
err := mssql.QueryRow(`
SELECT TOP 1 1
FROM dbo.prItemVariant
WHERE ItemTypeCode = @p1
AND ItemCode = @p2
AND (
ColorCode = @p3
OR (@p3 = '' AND (ColorCode IS NULL OR ColorCode = ''))
)
AND (
ItemDim1Code = @p4
OR (@p4 = '' AND (ItemDim1Code IS NULL OR ItemDim1Code = ''))
)
AND (
ItemDim2Code = @p5
OR (@p5 = '' AND (ItemDim2Code IS NULL OR ItemDim2Code = ''))
)
AND (
ItemDim3Code = @p6
OR (@p6 = '' AND (ItemDim3Code IS NULL OR ItemDim3Code = ''))
)
`, itemTypeCode, itemCode, colorCode, dim1, dim2, dim3).Scan(&exists)
if err == sql.ErrNoRows {
return false, nil
}
if err != nil {
return false, err
}
return true, nil
}
func InsertMissingVariantsTx(
tx *sql.Tx,
missing []models.OrderProductionMissingVariant,
username string,
cdItemByCode map[string]models.OrderProductionCdItemDraft,
) (int64, error) {
start := time.Now()
if len(missing) == 0 {
log.Printf("[InsertMissingVariantsTx] missing=0 inserted=0 duration_ms=0")
return 0, nil
}
var inserted int64
ensuredItems := make(map[string]struct{}, len(missing))
uniqueVariants := make([]models.OrderProductionMissingVariant, 0, len(missing))
seenVariants := make(map[string]struct{}, len(missing))
for _, v := range missing {
variantKey := strconv.FormatInt(int64(v.ItemTypeCode), 10) + "|" +
strings.ToUpper(strings.TrimSpace(v.ItemCode)) + "|" +
strings.ToUpper(strings.TrimSpace(v.ColorCode)) + "|" +
strings.ToUpper(strings.TrimSpace(v.ItemDim1Code)) + "|" +
strings.ToUpper(strings.TrimSpace(v.ItemDim2Code)) + "|" +
strings.ToUpper(strings.TrimSpace(v.ItemDim3Code))
if _, ok := seenVariants[variantKey]; ok {
continue
}
seenVariants[variantKey] = struct{}{}
uniqueVariants = append(uniqueVariants, v)
itemKey := strconv.FormatInt(int64(v.ItemTypeCode), 10) + "|" + v.ItemCode
if _, ok := ensuredItems[itemKey]; !ok {
draft, hasDraft := cdItemByCode[itemKey]
if !hasDraft {
draft, hasDraft = cdItemByCode[NormalizeCdItemMapKey(v.ItemTypeCode, v.ItemCode)]
}
var draftPtr *models.OrderProductionCdItemDraft
if hasDraft {
tmp := draft
draftPtr = &tmp
}
if err := ensureCdItemTx(tx, v.ItemTypeCode, v.ItemCode, username, draftPtr); err != nil {
return inserted, err
}
ensuredItems[itemKey] = struct{}{}
}
}
if len(uniqueVariants) == 0 {
return 0, nil
}
args := make([]any, 0, len(uniqueVariants)*6+1)
valueRows := make([]string, 0, len(uniqueVariants))
paramPos := 1
for _, v := range uniqueVariants {
valueRows = append(valueRows, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3, paramPos+4, paramPos+5))
args = append(args, v.ItemTypeCode, v.ItemCode, v.ColorCode, v.ItemDim1Code, v.ItemDim2Code, v.ItemDim3Code)
paramPos += 6
}
usernameParam := paramPos
args = append(args, username)
query := fmt.Sprintf(`
SET NOCOUNT ON;
;WITH Missing(ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code) AS (
SELECT *
FROM (VALUES %s) AS v(ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code)
)
INSERT INTO dbo.prItemVariant (
ItemTypeCode,
ItemCode,
ColorCode,
ItemDim1Code,
ItemDim2Code,
ItemDim3Code,
IsSalesOrderClosed,
IsPurchaseOrderClosed,
IsLocked,
IsBlocked,
CreatedUserName,
CreatedDate,
LastUpdatedUserName,
LastUpdatedDate,
RowGuid,
UseInternet,
IsStoreOrderClosed
)
SELECT
m.ItemTypeCode,
m.ItemCode,
m.ColorCode,
m.ItemDim1Code,
m.ItemDim2Code,
m.ItemDim3Code,
0, 0, 0, 0,
@p%d, GETDATE(), @p%d, GETDATE(),
NEWID(),
0,
0
FROM Missing m
LEFT JOIN dbo.prItemVariant pv
ON pv.ItemTypeCode = m.ItemTypeCode
AND pv.ItemCode = m.ItemCode
AND (
pv.ColorCode = m.ColorCode
OR (m.ColorCode = '' AND (pv.ColorCode IS NULL OR pv.ColorCode = ''))
)
AND (
pv.ItemDim1Code = m.ItemDim1Code
OR (m.ItemDim1Code = '' AND (pv.ItemDim1Code IS NULL OR pv.ItemDim1Code = ''))
)
AND (
pv.ItemDim2Code = m.ItemDim2Code
OR (m.ItemDim2Code = '' AND (pv.ItemDim2Code IS NULL OR pv.ItemDim2Code = ''))
)
AND (
pv.ItemDim3Code = m.ItemDim3Code
OR (m.ItemDim3Code = '' AND (pv.ItemDim3Code IS NULL OR pv.ItemDim3Code = ''))
)
WHERE pv.ItemCode IS NULL;
`, strings.Join(valueRows, ","), usernameParam, usernameParam)
res, err := tx.Exec(query, args...)
if err != nil {
return inserted, err
}
if rows, rowsErr := res.RowsAffected(); rowsErr == nil {
inserted += rows
}
log.Printf("[InsertMissingVariantsTx] missing=%d unique=%d ensuredItems=%d inserted=%d duration_ms=%d",
len(missing), len(uniqueVariants), len(ensuredItems), inserted, time.Since(start).Milliseconds())
return inserted, nil
}
func NormalizeCdItemMapKey(itemTypeCode int16, itemCode string) string {
return strconv.FormatInt(int64(itemTypeCode), 10) + "|" + strings.ToUpper(strings.TrimSpace(itemCode))
}
func ensureCdItemTx(
tx *sql.Tx,
itemTypeCode int16,
itemCode string,
username string,
draft *models.OrderProductionCdItemDraft,
) error {
_, err := tx.Exec(`
IF NOT EXISTS (
SELECT 1
FROM dbo.cdItem
WHERE ItemTypeCode = @p1
AND ItemCode = @p2
)
BEGIN
;WITH Template AS (
SELECT TOP 1
ItemDimTypeCode, ProductTypeCode, ProductHierarchyID,
UnitOfMeasureCode1, UnitOfMeasureCode2, UnitConvertRate, UnitConvertRateNotFixed,
UseInternet, UsePOS, UseStore, EnablePartnerCompanies, UseManufacturing, UseSerialNumber,
GenerateOpticalDataMatrixCode, ByWeight, SupplyPeriod, GuaranteePeriod, ShelfLife, OrderLeadTime,
ItemAccountGrCode, ItemTaxGrCode, ItemPaymentPlanGrCode, ItemDiscountGrCode, ItemVendorGrCode,
PromotionGroupCode, PromotionGroupCode2, ProductCollectionGrCode, StorePriceLevelCode, PerceptionOfFashionCode,
CommercialRoleCode, StoreCapacityLevelCode, CustomsTariffNumberCode, IsFixedExpense, BOMEntityCode, CompanyCode,
IsBlocked, IsLocked, LockedDate, IsSalesOrderClosed, IsPurchaseOrderClosed, UseRoll, UseBatch,
MaxCreditCardInstallmentCount, GenerateSerialNumber, IsSubsequentDeliveryForR, IsSubsequentDeliveryForRI,
IGACommissionGroup, UniFreeCommissionGroup, CustomsProductGroupCode, IsUTSDeclaratedItem, IsStoreOrderClosed
FROM dbo.cdItem WITH (UPDLOCK, HOLDLOCK)
WHERE ItemTypeCode = @p1
AND ItemCode LIKE 'U%'
ORDER BY CreatedDate DESC
)
INSERT INTO dbo.cdItem (
ItemTypeCode, ItemCode,
ItemDimTypeCode, ProductTypeCode, ProductHierarchyID,
UnitOfMeasureCode1, UnitOfMeasureCode2, UnitConvertRate, UnitConvertRateNotFixed,
UseInternet, UsePOS, UseStore, EnablePartnerCompanies, UseManufacturing, UseSerialNumber,
GenerateOpticalDataMatrixCode, ByWeight, SupplyPeriod, GuaranteePeriod, ShelfLife, OrderLeadTime,
ItemAccountGrCode, ItemTaxGrCode, ItemPaymentPlanGrCode, ItemDiscountGrCode, ItemVendorGrCode,
PromotionGroupCode, PromotionGroupCode2, ProductCollectionGrCode, StorePriceLevelCode, PerceptionOfFashionCode,
CommercialRoleCode, StoreCapacityLevelCode, CustomsTariffNumberCode, IsFixedExpense, BOMEntityCode, CompanyCode,
IsBlocked, IsLocked, LockedDate, IsSalesOrderClosed, IsPurchaseOrderClosed,
CreatedUserName, CreatedDate, LastUpdatedUserName, LastUpdatedDate, RowGuid,
UseRoll, UseBatch, MaxCreditCardInstallmentCount, GenerateSerialNumber,
IsSubsequentDeliveryForR, IsSubsequentDeliveryForRI,
IGACommissionGroup, UniFreeCommissionGroup, CustomsProductGroupCode, IsUTSDeclaratedItem, IsStoreOrderClosed
)
SELECT
@p1, @p2,
t.ItemDimTypeCode, t.ProductTypeCode, t.ProductHierarchyID,
t.UnitOfMeasureCode1, t.UnitOfMeasureCode2, t.UnitConvertRate, t.UnitConvertRateNotFixed,
t.UseInternet, t.UsePOS, t.UseStore, t.EnablePartnerCompanies, t.UseManufacturing, t.UseSerialNumber,
t.GenerateOpticalDataMatrixCode, t.ByWeight, t.SupplyPeriod, t.GuaranteePeriod, t.ShelfLife, t.OrderLeadTime,
t.ItemAccountGrCode, t.ItemTaxGrCode, t.ItemPaymentPlanGrCode, t.ItemDiscountGrCode, t.ItemVendorGrCode,
t.PromotionGroupCode, t.PromotionGroupCode2, t.ProductCollectionGrCode, t.StorePriceLevelCode, t.PerceptionOfFashionCode,
t.CommercialRoleCode, t.StoreCapacityLevelCode, t.CustomsTariffNumberCode, t.IsFixedExpense, t.BOMEntityCode, t.CompanyCode,
t.IsBlocked, t.IsLocked, t.LockedDate, t.IsSalesOrderClosed, t.IsPurchaseOrderClosed,
@p3, GETDATE(), @p3, GETDATE(), NEWID(),
t.UseRoll, t.UseBatch, t.MaxCreditCardInstallmentCount, t.GenerateSerialNumber,
t.IsSubsequentDeliveryForR, t.IsSubsequentDeliveryForRI,
t.IGACommissionGroup, t.UniFreeCommissionGroup, t.CustomsProductGroupCode, t.IsUTSDeclaratedItem, t.IsStoreOrderClosed
FROM Template t;
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO dbo.cdItem (
ItemTypeCode, ItemCode,
ItemDimTypeCode, ProductTypeCode, ProductHierarchyID,
UnitOfMeasureCode1, UnitOfMeasureCode2, UnitConvertRate, UnitConvertRateNotFixed,
UseInternet, UsePOS, UseStore, EnablePartnerCompanies, UseManufacturing, UseSerialNumber,
GenerateOpticalDataMatrixCode, ByWeight, SupplyPeriod, GuaranteePeriod, ShelfLife, OrderLeadTime,
ItemAccountGrCode, ItemTaxGrCode, ItemPaymentPlanGrCode, ItemDiscountGrCode, ItemVendorGrCode,
PromotionGroupCode, PromotionGroupCode2, ProductCollectionGrCode, StorePriceLevelCode, PerceptionOfFashionCode,
CommercialRoleCode, StoreCapacityLevelCode, CustomsTariffNumberCode, IsFixedExpense, BOMEntityCode, CompanyCode,
IsBlocked, IsLocked, LockedDate, IsSalesOrderClosed, IsPurchaseOrderClosed,
CreatedUserName, CreatedDate, LastUpdatedUserName, LastUpdatedDate, RowGuid,
UseRoll, UseBatch, MaxCreditCardInstallmentCount, GenerateSerialNumber,
IsSubsequentDeliveryForR, IsSubsequentDeliveryForRI,
IGACommissionGroup, UniFreeCommissionGroup, CustomsProductGroupCode, IsUTSDeclaratedItem, IsStoreOrderClosed
)
VALUES (
@p1, @p2,
2, 1, 2,
'AD', '', 0, 0,
1, 1, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0,
'', '%10', '', '', '',
'', '', '0', '0', '0',
'0', '', '', 0, '', '1',
0, 0, '1900-01-01', 0, 0,
@p3, GETDATE(), @p3, GETDATE(), NEWID(),
0, 0, 12, 0,
0, 0,
'', '', '0', 0, 0
);
END
END
`, itemTypeCode, itemCode, username)
if err != nil {
return err
}
if draft == nil {
return nil
}
_, err = tx.Exec(`
UPDATE dbo.cdItem
SET
ItemDimTypeCode = COALESCE(@p3, ItemDimTypeCode),
ProductTypeCode = COALESCE(@p4, ProductTypeCode),
ProductHierarchyID = COALESCE(@p5, ProductHierarchyID),
UnitOfMeasureCode1 = COALESCE(NULLIF(@p6,''), UnitOfMeasureCode1),
ItemAccountGrCode = COALESCE(NULLIF(@p7,''), ItemAccountGrCode),
ItemTaxGrCode = CASE
WHEN NULLIF(@p8,'') IS NULL THEN ItemTaxGrCode
WHEN EXISTS (
SELECT 1
FROM dbo.cdItemTaxGr g WITH(NOLOCK)
WHERE LTRIM(RTRIM(g.ItemTaxGrCode)) = LTRIM(RTRIM(@p8))
) THEN @p8
ELSE ItemTaxGrCode
END,
ItemPaymentPlanGrCode = COALESCE(NULLIF(@p9,''), ItemPaymentPlanGrCode),
ItemDiscountGrCode = COALESCE(NULLIF(@p10,''), ItemDiscountGrCode),
ItemVendorGrCode = COALESCE(NULLIF(@p11,''), ItemVendorGrCode),
PromotionGroupCode = COALESCE(NULLIF(@p12,''), PromotionGroupCode),
ProductCollectionGrCode = COALESCE(NULLIF(@p13,''), ProductCollectionGrCode),
StorePriceLevelCode = COALESCE(NULLIF(@p14,''), StorePriceLevelCode),
PerceptionOfFashionCode = COALESCE(NULLIF(@p15,''), PerceptionOfFashionCode),
CommercialRoleCode = COALESCE(NULLIF(@p16,''), CommercialRoleCode),
StoreCapacityLevelCode = COALESCE(NULLIF(@p17,''), StoreCapacityLevelCode),
CustomsTariffNumberCode = COALESCE(NULLIF(@p18,''), CustomsTariffNumberCode),
CompanyCode = COALESCE(NULLIF(@p19,''), CompanyCode),
LastUpdatedUserName = @p20,
LastUpdatedDate = GETDATE()
WHERE ItemTypeCode = @p1
AND ItemCode = @p2;
`,
itemTypeCode,
itemCode,
draft.ItemDimTypeCode,
draft.ProductTypeCode,
draft.ProductHierarchyID,
draft.UnitOfMeasureCode1,
draft.ItemAccountGrCode,
draft.ItemTaxGrCode,
draft.ItemPaymentPlanGrCode,
draft.ItemDiscountGrCode,
draft.ItemVendorGrCode,
draft.PromotionGroupCode,
draft.ProductCollectionGrCode,
draft.StorePriceLevelCode,
draft.PerceptionOfFashionCode,
draft.CommercialRoleCode,
draft.StoreCapacityLevelCode,
draft.CustomsTariffNumberCode,
draft.CompanyCode,
username,
)
return err
}
func UpdateOrderLinesTx(tx *sql.Tx, orderHeaderID string, lines []models.OrderProductionUpdateLine, username string) (int64, error) {
if len(lines) == 0 {
return 0, nil
}
const chunkSize = 300
var updated int64
for i := 0; i < len(lines); i += chunkSize {
end := i + chunkSize
if end > len(lines) {
end = len(lines)
}
chunk := lines[i:end]
values := make([]string, 0, len(chunk))
args := make([]any, 0, len(chunk)*8+2)
paramPos := 1
for _, line := range chunk {
var itemDim1 any
if line.ItemDim1Code != nil {
itemDim1 = strings.TrimSpace(*line.ItemDim1Code)
}
values = append(values, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d,@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3, paramPos+4, paramPos+5, paramPos+6, paramPos+7))
args = append(args,
strings.TrimSpace(line.OrderLineID),
line.NewItemCode,
line.NewColor,
itemDim1,
line.NewDim2,
line.NewDesc,
line.OldDueDate,
line.NewDueDate,
)
paramPos += 8
}
orderHeaderParam := paramPos
usernameParam := paramPos + 1
args = append(args, orderHeaderID, username)
query := fmt.Sprintf(`
SET NOCOUNT ON;
DECLARE @updated TABLE (OrderLineID UNIQUEIDENTIFIER);
;WITH src (OrderLineID, NewItemCode, NewColor, ItemDim1Code, NewDim2, NewDesc, OldDueDate, NewDueDate) AS (
SELECT *
FROM (VALUES %s) AS v (OrderLineID, NewItemCode, NewColor, ItemDim1Code, NewDim2, NewDesc, OldDueDate, NewDueDate)
)
UPDATE l
SET
l.ItemCode = s.NewItemCode,
l.ColorCode = s.NewColor,
l.ItemDim1Code = COALESCE(s.ItemDim1Code, l.ItemDim1Code),
l.ItemDim2Code = s.NewDim2,
l.LineDescription = COALESCE(NULLIF(s.NewDesc,''), l.LineDescription),
l.DeliveryDate = CASE WHEN ISDATE(s.NewDueDate) = 1 THEN CAST(s.NewDueDate AS DATETIME) ELSE l.DeliveryDate END,
l.LastUpdatedUserName = @p%d,
l.LastUpdatedDate = GETDATE()
OUTPUT inserted.OrderLineID INTO @updated(OrderLineID)
FROM dbo.trOrderLine l
JOIN src s
ON l.OrderLineID = CONVERT(UNIQUEIDENTIFIER, s.OrderLineID)
WHERE l.OrderHeaderID = CONVERT(UNIQUEIDENTIFIER, @p%d);
SELECT COUNT(1) AS UpdatedCount FROM @updated;
`, strings.Join(values, ","), usernameParam, orderHeaderParam)
chunkStart := time.Now()
var chunkUpdated int64
execErr := tx.QueryRow(query, args...).Scan(&chunkUpdated)
if execErr != nil {
log.Printf("[UpdateOrderLinesTx] ERROR orderHeaderID=%s chunk=%d-%d err=%v", orderHeaderID, i, end, execErr)
return updated, fmt.Errorf("update lines chunk failed chunkStart=%d chunkEnd=%d duration_ms=%d: %w", i, end, time.Since(chunkStart).Milliseconds(), execErr)
}
log.Printf("[UpdateOrderLinesTx] orderHeaderID=%s chunk=%d-%d updated=%d duration_ms=%d", orderHeaderID, i, end, chunkUpdated, time.Since(chunkStart).Milliseconds())
updated += chunkUpdated
}
return updated, nil
}
func VerifyOrderLineUpdatesTx(tx *sql.Tx, orderHeaderID string, lines []models.OrderProductionUpdateLine) (int64, []string, error) {
if len(lines) == 0 {
return 0, nil, nil
}
const chunkSize = 300
var mismatchCount int64
samples := make([]string, 0, 5)
for i := 0; i < len(lines); i += chunkSize {
end := i + chunkSize
if end > len(lines) {
end = len(lines)
}
chunk := lines[i:end]
values := make([]string, 0, len(chunk))
args := make([]any, 0, len(chunk)*4+1)
paramPos := 1
for _, line := range chunk {
values = append(values, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3))
args = append(args,
strings.TrimSpace(line.OrderLineID),
strings.ToUpper(strings.TrimSpace(line.NewItemCode)),
strings.ToUpper(strings.TrimSpace(line.NewColor)),
strings.ToUpper(strings.TrimSpace(line.NewDim2)),
)
paramPos += 4
}
orderHeaderParam := paramPos
args = append(args, orderHeaderID)
query := fmt.Sprintf(`
SET NOCOUNT ON;
WITH src (OrderLineID, NewItemCode, NewColor, NewDim2) AS (
SELECT *
FROM (VALUES %s) v(OrderLineID, NewItemCode, NewColor, NewDim2)
)
SELECT
s.OrderLineID,
ISNULL(UPPER(LTRIM(RTRIM(l.ItemCode))), '') AS ActualItemCode,
ISNULL(UPPER(LTRIM(RTRIM(l.ColorCode))), '') AS ActualColorCode,
ISNULL(UPPER(LTRIM(RTRIM(l.ItemDim2Code))), '') AS ActualDim2Code,
s.NewItemCode,
s.NewColor,
s.NewDim2
FROM src s
JOIN dbo.trOrderLine l
ON l.OrderLineID = CONVERT(UNIQUEIDENTIFIER, s.OrderLineID)
WHERE l.OrderHeaderID = CONVERT(UNIQUEIDENTIFIER, @p%d)
AND (
ISNULL(UPPER(LTRIM(RTRIM(l.ItemCode))), '') <> s.NewItemCode OR
ISNULL(UPPER(LTRIM(RTRIM(l.ColorCode))), '') <> s.NewColor OR
ISNULL(UPPER(LTRIM(RTRIM(l.ItemDim2Code))), '') <> s.NewDim2
);
`, strings.Join(values, ","), orderHeaderParam)
rows, err := tx.Query(query, args...)
if err != nil {
return mismatchCount, samples, err
}
for rows.Next() {
var lineID, actualItem, actualColor, actualDim2, expectedItem, expectedColor, expectedDim2 string
if err := rows.Scan(&lineID, &actualItem, &actualColor, &actualDim2, &expectedItem, &expectedColor, &expectedDim2); err != nil {
rows.Close()
return mismatchCount, samples, err
}
mismatchCount++
if len(samples) < 5 {
samples = append(samples, fmt.Sprintf(
"lineID=%s expected=(%s,%s,%s) actual=(%s,%s,%s)",
lineID, expectedItem, expectedColor, expectedDim2, actualItem, actualColor, actualDim2,
))
}
}
if err := rows.Err(); err != nil {
rows.Close()
return mismatchCount, samples, err
}
rows.Close()
}
return mismatchCount, samples, nil
}
func UpdateOrderHeaderAverageDueDateTx(tx *sql.Tx, orderHeaderID string, averageDueDate *string, username string) error {
if averageDueDate == nil {
return nil
}
dueDate := strings.TrimSpace(*averageDueDate)
if dueDate != "" {
if _, err := time.Parse("2006-01-02", dueDate); err != nil {
return fmt.Errorf("invalid header average due date %q: %w", dueDate, err)
}
}
_, err := tx.Exec(`
UPDATE dbo.trOrderHeader
SET
AverageDueDate = CASE WHEN @p1 = '' THEN NULL ELSE CAST(@p1 AS DATETIME) END,
LastUpdatedUserName = @p2,
LastUpdatedDate = GETDATE()
WHERE OrderHeaderID = @p3;
`, dueDate, username, orderHeaderID)
return err
}
func TouchOrderHeaderTx(tx *sql.Tx, orderHeaderID string, username string) (int64, error) {
res, err := tx.Exec(`
UPDATE dbo.trOrderHeader
SET
LastUpdatedUserName = @p1,
LastUpdatedDate = GETDATE()
WHERE OrderHeaderID = @p2;
`, username, orderHeaderID)
if err != nil {
return 0, err
}
rows, rowsErr := res.RowsAffected()
if rowsErr != nil {
return 0, nil
}
return rows, nil
}
type sqlQueryRower interface {
QueryRow(query string, args ...any) *sql.Row
}
type plannedProductionBarcode struct {
Barcode string
BarcodeTypeCode string
ItemTypeCode int16
ItemCode string
ColorCode string
ItemDim1Code string
ItemDim2Code string
ItemDim3Code string
}
func barcodeTypeExists(q sqlQueryRower, barcodeTypeCode string) (bool, error) {
var exists int
err := q.QueryRow(`
SELECT TOP 1 1
FROM dbo.cdBarcodeType
WHERE BarcodeTypeCode = @p1
`, strings.TrimSpace(barcodeTypeCode)).Scan(&exists)
if err == sql.ErrNoRows {
return false, nil
}
if err != nil {
return false, err
}
return true, nil
}
func barcodeExists(q sqlQueryRower, barcode string) (bool, error) {
var exists int
err := q.QueryRow(`
SELECT TOP 1 1
FROM dbo.prItemBarcode WITH (UPDLOCK, HOLDLOCK)
WHERE Barcode = @p1
`, strings.TrimSpace(barcode)).Scan(&exists)
if err == sql.ErrNoRows {
return false, nil
}
if err != nil {
return false, err
}
return true, nil
}
func existingVariantBarcode(
q sqlQueryRower,
barcodeTypeCode string,
itemTypeCode int16,
itemCode string,
colorCode string,
dim1 string,
dim2 string,
dim3 string,
) (string, bool, error) {
var barcode string
err := q.QueryRow(`
SELECT TOP 1 LTRIM(RTRIM(ISNULL(Barcode, '')))
FROM dbo.prItemBarcode WITH (UPDLOCK, HOLDLOCK)
WHERE BarcodeTypeCode = @p1
AND ItemTypeCode = @p2
AND ISNULL(LTRIM(RTRIM(ItemCode)), '') = @p3
AND ISNULL(LTRIM(RTRIM(ColorCode)), '') = @p4
AND ISNULL(LTRIM(RTRIM(ItemDim1Code)), '') = @p5
AND ISNULL(LTRIM(RTRIM(ItemDim2Code)), '') = @p6
AND ISNULL(LTRIM(RTRIM(ItemDim3Code)), '') = @p7
AND ISNULL(LTRIM(RTRIM(UnitOfMeasureCode)), '') = 'AD'
ORDER BY
CASE
WHEN ISNUMERIC(Barcode) = 1
THEN CAST(Barcode AS BIGINT)
ELSE 0
END DESC,
Barcode DESC
`,
strings.TrimSpace(barcodeTypeCode),
itemTypeCode,
strings.TrimSpace(itemCode),
strings.TrimSpace(colorCode),
strings.TrimSpace(dim1),
strings.TrimSpace(dim2),
strings.TrimSpace(dim3),
).Scan(&barcode)
if err == sql.ErrNoRows {
return "", false, nil
}
if err != nil {
return "", false, err
}
return strings.TrimSpace(barcode), true, nil
}
func maxNumericBarcode(q sqlQueryRower) (int64, error) {
var maxBarcode int64
err := q.QueryRow(`
SELECT ISNULL(MAX(
CASE
WHEN ISNUMERIC(Barcode) = 1
THEN CAST(Barcode AS BIGINT)
ELSE NULL
END
), 0)
FROM dbo.prItemBarcode WITH (UPDLOCK, HOLDLOCK)
`).Scan(&maxBarcode)
return maxBarcode, err
}
func ValidateProductionBarcodePlan(q sqlQueryRower, variants []models.OrderProductionMissingVariant, barcodeTypeCode string) ([]models.OrderProductionBarcodeValidation, error) {
typeCode := strings.ToUpper(strings.TrimSpace(barcodeTypeCode))
if len(variants) == 0 {
return nil, nil
}
validations := make([]models.OrderProductionBarcodeValidation, 0)
typeExists, err := barcodeTypeExists(q, typeCode)
if err != nil {
return nil, err
}
if !typeExists {
validations = append(validations, models.OrderProductionBarcodeValidation{
Code: "invalid_barcode_type",
Message: fmt.Sprintf("Barkod tipi bulunamadi: %s", typeCode),
BarcodeTypeCode: typeCode,
})
return validations, nil
}
sorted := append([]models.OrderProductionMissingVariant(nil), variants...)
sort.Slice(sorted, func(i, j int) bool {
left := sorted[i]
right := sorted[j]
leftKey := fmt.Sprintf("%05d|%s|%s|%s|%s|%s", left.ItemTypeCode, left.ItemCode, left.ColorCode, left.ItemDim1Code, left.ItemDim2Code, left.ItemDim3Code)
rightKey := fmt.Sprintf("%05d|%s|%s|%s|%s|%s", right.ItemTypeCode, right.ItemCode, right.ColorCode, right.ItemDim1Code, right.ItemDim2Code, right.ItemDim3Code)
return leftKey < rightKey
})
maxBarcode, err := maxNumericBarcode(q)
if err != nil {
return nil, err
}
nextOffset := int64(0)
planned := make(map[string]struct{}, len(sorted))
for _, variant := range sorted {
existingBarcode, exists, err := existingVariantBarcode(q, typeCode, variant.ItemTypeCode, variant.ItemCode, variant.ColorCode, variant.ItemDim1Code, variant.ItemDim2Code, variant.ItemDim3Code)
if err != nil {
return nil, err
}
if exists && existingBarcode != "" {
continue
}
nextOffset++
barcode := strconv.FormatInt(maxBarcode+nextOffset, 10)
if _, duplicated := planned[barcode]; duplicated {
validations = append(validations, models.OrderProductionBarcodeValidation{
Code: "barcode_duplicate_in_plan",
Message: fmt.Sprintf("Planlanan barkod ayni istekte birden fazla kez olusuyor: %s", barcode),
Barcode: barcode,
BarcodeTypeCode: typeCode,
ItemTypeCode: variant.ItemTypeCode,
ItemCode: strings.TrimSpace(variant.ItemCode),
ColorCode: strings.TrimSpace(variant.ColorCode),
ItemDim1Code: strings.TrimSpace(variant.ItemDim1Code),
ItemDim2Code: strings.TrimSpace(variant.ItemDim2Code),
ItemDim3Code: strings.TrimSpace(variant.ItemDim3Code),
})
continue
}
planned[barcode] = struct{}{}
inUse, err := barcodeExists(q, barcode)
if err != nil {
return nil, err
}
if inUse {
validations = append(validations, models.OrderProductionBarcodeValidation{
Code: "barcode_in_use",
Message: fmt.Sprintf("Barkod daha once kullanilmis: %s (%s / %s / %s / %s)", barcode, strings.TrimSpace(variant.ItemCode), strings.TrimSpace(variant.ColorCode), strings.TrimSpace(variant.ItemDim1Code), strings.TrimSpace(variant.ItemDim2Code)),
Barcode: barcode,
BarcodeTypeCode: typeCode,
ItemTypeCode: variant.ItemTypeCode,
ItemCode: strings.TrimSpace(variant.ItemCode),
ColorCode: strings.TrimSpace(variant.ColorCode),
ItemDim1Code: strings.TrimSpace(variant.ItemDim1Code),
ItemDim2Code: strings.TrimSpace(variant.ItemDim2Code),
ItemDim3Code: strings.TrimSpace(variant.ItemDim3Code),
})
}
}
return validations, nil
}
func InsertItemBarcodesTx(tx *sql.Tx, orderHeaderID string, lines []models.OrderProductionUpdateLine, username string) (int64, error) {
start := time.Now()
if len(lines) == 0 {
log.Printf("[InsertItemBarcodesTx] lines=0 inserted=0 duration_ms=0")
return 0, nil
}
lineIDs := make([]string, 0, len(lines))
seen := make(map[string]struct{}, len(lines))
for _, line := range lines {
lineID := strings.TrimSpace(line.OrderLineID)
if lineID == "" {
continue
}
if _, ok := seen[lineID]; ok {
continue
}
seen[lineID] = struct{}{}
lineIDs = append(lineIDs, lineID)
}
if len(lineIDs) == 0 {
log.Printf("[InsertItemBarcodesTx] uniqueLineIDs=0 inserted=0")
return 0, nil
}
var inserted int64
singleLineQuery := `
SET NOCOUNT ON;
INSERT INTO dbo.prItemBarcode
(
Barcode,
BarcodeTypeCode,
ItemTypeCode,
ItemCode,
ColorCode,
ItemDim1Code,
ItemDim2Code,
ItemDim3Code,
UnitOfMeasureCode,
Qty,
CreatedUserName,
CreatedDate,
LastUpdatedUserName,
LastUpdatedDate,
RowGuid
)
SELECT
CAST(seed.MaxBarcode + 1 AS NVARCHAR(50)),
'BAGGI3',
src.ItemTypeCode,
src.ItemCode,
src.ColorCode,
src.ItemDim1Code,
src.ItemDim2Code,
src.ItemDim3Code,
'AD',
1,
@p3,
GETDATE(),
@p3,
GETDATE(),
NEWID()
FROM (
SELECT DISTINCT
l.ItemTypeCode,
UPPER(LTRIM(RTRIM(ISNULL(l.ItemCode,'')))) AS ItemCode,
UPPER(LTRIM(RTRIM(ISNULL(l.ColorCode,'')))) AS ColorCode,
UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim1Code,'')))) AS ItemDim1Code,
UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim2Code,'')))) AS ItemDim2Code,
UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim3Code,'')))) AS ItemDim3Code
FROM dbo.trOrderLine l
WHERE l.OrderHeaderID = @p2
AND CAST(l.OrderLineID AS NVARCHAR(50)) = @p1
AND NULLIF(LTRIM(RTRIM(ISNULL(l.ItemCode,''))), '') IS NOT NULL
) src
CROSS JOIN (
SELECT
CASE
WHEN ISNULL(MAX(
CASE
WHEN LTRIM(RTRIM(ISNULL(Barcode,''))) NOT LIKE '%%[^0-9]%%'
AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) BETWEEN 1 AND 18
THEN CAST(LTRIM(RTRIM(ISNULL(Barcode,''))) AS BIGINT)
ELSE NULL
END
), 0) < 36999999
THEN 36999999
ELSE ISNULL(MAX(
CASE
WHEN LTRIM(RTRIM(ISNULL(Barcode,''))) NOT LIKE '%%[^0-9]%%'
AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) BETWEEN 1 AND 18
THEN CAST(LTRIM(RTRIM(ISNULL(Barcode,''))) AS BIGINT)
ELSE NULL
END
), 0)
END AS MaxBarcode
FROM dbo.prItemBarcode
WHERE BarcodeTypeCode = 'BAGGI3'
AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) <= 8
) seed
WHERE NOT EXISTS (
SELECT 1
FROM dbo.prItemBarcode b
WHERE b.ItemTypeCode = src.ItemTypeCode
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemCode,'')))) = src.ItemCode
AND UPPER(LTRIM(RTRIM(ISNULL(b.ColorCode,'')))) = src.ColorCode
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim1Code,'')))) = src.ItemDim1Code
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim2Code,'')))) = src.ItemDim2Code
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim3Code,'')))) = src.ItemDim3Code
);
`
execSingle := func(globalIndex int, lineID string) error {
lineStart := time.Now()
res, err := tx.Exec(singleLineQuery, lineID, orderHeaderID, username)
if err != nil {
if isDuplicateBarcodeInsertErr(err) {
log.Printf("[InsertItemBarcodesTx] skip duplicate lineIndex=%d lineID=%s err=%v", globalIndex, lineID, err)
return nil
}
return fmt.Errorf("upsert item barcodes chunk failed chunkStart=%d chunkEnd=%d duration_ms=%d: %w", globalIndex, globalIndex+1, time.Since(lineStart).Milliseconds(), err)
}
rows, _ := res.RowsAffected()
inserted += rows
log.Printf(
"[InsertItemBarcodesTx] lineIndex=%d lineID=%s inserted=%d cumulative=%d duration_ms=%d",
globalIndex,
lineID,
rows,
inserted,
time.Since(lineStart).Milliseconds(),
)
return nil
}
const chunkSize = 200
for i := 0; i < len(lineIDs); i += chunkSize {
end := i + chunkSize
if end > len(lineIDs) {
end = len(lineIDs)
}
chunk := lineIDs[i:end]
values := make([]string, 0, len(chunk))
args := make([]any, 0, len(chunk)+2)
paramPos := 1
for _, lineID := range chunk {
values = append(values, fmt.Sprintf("(@p%d)", paramPos))
args = append(args, lineID)
paramPos++
}
orderHeaderParam := paramPos
usernameParam := paramPos + 1
args = append(args, orderHeaderID, username)
batchQuery := fmt.Sprintf(`
SET NOCOUNT ON;
INSERT INTO dbo.prItemBarcode
(
Barcode,
BarcodeTypeCode,
ItemTypeCode,
ItemCode,
ColorCode,
ItemDim1Code,
ItemDim2Code,
ItemDim3Code,
UnitOfMeasureCode,
Qty,
CreatedUserName,
CreatedDate,
LastUpdatedUserName,
LastUpdatedDate,
RowGuid
)
SELECT
CAST(seed.MaxBarcode + ROW_NUMBER() OVER (
ORDER BY src.ItemTypeCode, src.ItemCode, src.ColorCode, src.ItemDim1Code, src.ItemDim2Code, src.ItemDim3Code
) AS NVARCHAR(50)),
'BAGGI3',
src.ItemTypeCode,
src.ItemCode,
src.ColorCode,
src.ItemDim1Code,
src.ItemDim2Code,
src.ItemDim3Code,
'AD',
1,
@p%d,
GETDATE(),
@p%d,
GETDATE(),
NEWID()
FROM (
SELECT DISTINCT
l.ItemTypeCode,
UPPER(LTRIM(RTRIM(ISNULL(l.ItemCode,'')))) AS ItemCode,
UPPER(LTRIM(RTRIM(ISNULL(l.ColorCode,'')))) AS ColorCode,
UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim1Code,'')))) AS ItemDim1Code,
UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim2Code,'')))) AS ItemDim2Code,
UPPER(LTRIM(RTRIM(ISNULL(l.ItemDim3Code,'')))) AS ItemDim3Code
FROM dbo.trOrderLine l
JOIN (VALUES %s) ids(OrderLineID)
ON CAST(l.OrderLineID AS NVARCHAR(50)) = ids.OrderLineID
WHERE l.OrderHeaderID = @p%d
AND NULLIF(LTRIM(RTRIM(ISNULL(l.ItemCode,''))), '') IS NOT NULL
) src
CROSS JOIN (
SELECT
CASE
WHEN ISNULL(MAX(
CASE
WHEN LTRIM(RTRIM(ISNULL(Barcode,''))) NOT LIKE '%%[^0-9]%%'
AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) BETWEEN 1 AND 18
THEN CAST(LTRIM(RTRIM(ISNULL(Barcode,''))) AS BIGINT)
ELSE NULL
END
), 0) < 36999999
THEN 36999999
ELSE ISNULL(MAX(
CASE
WHEN LTRIM(RTRIM(ISNULL(Barcode,''))) NOT LIKE '%%[^0-9]%%'
AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) BETWEEN 1 AND 18
THEN CAST(LTRIM(RTRIM(ISNULL(Barcode,''))) AS BIGINT)
ELSE NULL
END
), 0)
END AS MaxBarcode
FROM dbo.prItemBarcode
WHERE BarcodeTypeCode = 'BAGGI3'
AND LEN(LTRIM(RTRIM(ISNULL(Barcode,'')))) <= 8
) seed
WHERE NOT EXISTS (
SELECT 1
FROM dbo.prItemBarcode b
WHERE b.ItemTypeCode = src.ItemTypeCode
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemCode,'')))) = src.ItemCode
AND UPPER(LTRIM(RTRIM(ISNULL(b.ColorCode,'')))) = src.ColorCode
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim1Code,'')))) = src.ItemDim1Code
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim2Code,'')))) = src.ItemDim2Code
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim3Code,'')))) = src.ItemDim3Code
);
`, usernameParam, usernameParam, strings.Join(values, ","), orderHeaderParam)
chunkStart := time.Now()
res, err := tx.Exec(batchQuery, args...)
if err == nil {
rows, _ := res.RowsAffected()
inserted += rows
log.Printf(
"[InsertItemBarcodesTx] batch=%d-%d inserted=%d cumulative=%d duration_ms=%d",
i,
end,
rows,
inserted,
time.Since(chunkStart).Milliseconds(),
)
continue
}
log.Printf("[InsertItemBarcodesTx] batch fallback=%d-%d err=%v", i, end, err)
for j, lineID := range chunk {
if lineErr := execSingle(i+j, lineID); lineErr != nil {
log.Printf("[InsertItemBarcodesTx] ERROR lineIndex=%d lineID=%s err=%v", i+j, lineID, lineErr)
return inserted, lineErr
}
}
}
log.Printf(
"[InsertItemBarcodesTx] lines=%d unique=%d inserted=%d duration_ms=%d",
len(lines),
len(lineIDs),
inserted,
time.Since(start).Milliseconds(),
)
return inserted, nil
}
func InsertItemBarcodesByTargetsTx(tx *sql.Tx, targets []models.OrderProductionMissingVariant, username string) (int64, error) {
start := time.Now()
if len(targets) == 0 {
log.Printf("[InsertItemBarcodesByTargetsTx] targets=0 inserted=0 duration_ms=0")
return 0, nil
}
uniqueTargets := make([]models.OrderProductionMissingVariant, 0, len(targets))
seen := make(map[string]struct{}, len(targets))
for _, t := range targets {
itemCode := strings.ToUpper(strings.TrimSpace(t.ItemCode))
if itemCode == "" {
continue
}
key := fmt.Sprintf("%d|%s|%s|%s|%s|%s",
t.ItemTypeCode,
itemCode,
strings.ToUpper(strings.TrimSpace(t.ColorCode)),
strings.ToUpper(strings.TrimSpace(t.ItemDim1Code)),
strings.ToUpper(strings.TrimSpace(t.ItemDim2Code)),
strings.ToUpper(strings.TrimSpace(t.ItemDim3Code)),
)
if _, ok := seen[key]; ok {
continue
}
seen[key] = struct{}{}
t.ItemCode = itemCode
t.ColorCode = strings.ToUpper(strings.TrimSpace(t.ColorCode))
t.ItemDim1Code = strings.ToUpper(strings.TrimSpace(t.ItemDim1Code))
t.ItemDim2Code = strings.ToUpper(strings.TrimSpace(t.ItemDim2Code))
t.ItemDim3Code = strings.ToUpper(strings.TrimSpace(t.ItemDim3Code))
uniqueTargets = append(uniqueTargets, t)
}
if len(uniqueTargets) == 0 {
log.Printf("[InsertItemBarcodesByTargetsTx] targets=%d unique=0 inserted=0 duration_ms=%d", len(targets), time.Since(start).Milliseconds())
return 0, nil
}
if err := ensureTxStillActive(tx, "InsertItemBarcodesByTargetsTx/start"); err != nil {
return 0, err
}
// Barcode seed'i hem prItemBarcode hem de (varsa) tbStokBarkodu uzerinden
// kilitli okuyarak hesapla; trigger tarafindaki duplicate riskini azalt.
var maxBarcode int64
maxPrQuery := `
SELECT ISNULL(MAX(v.BarcodeNum), 0)
FROM (
SELECT
CASE
WHEN LTRIM(RTRIM(ISNULL(pb.Barcode,''))) NOT LIKE '%[^0-9]%'
AND LEN(LTRIM(RTRIM(ISNULL(pb.Barcode,'')))) BETWEEN 1 AND 18
THEN CAST(LTRIM(RTRIM(ISNULL(pb.Barcode,''))) AS BIGINT)
ELSE NULL
END AS BarcodeNum
FROM dbo.prItemBarcode pb WITH (UPDLOCK, HOLDLOCK, TABLOCKX)
WHERE pb.BarcodeTypeCode = 'BAGGI3'
) v
WHERE v.BarcodeNum IS NOT NULL;
`
if err := tx.QueryRow(maxPrQuery).Scan(&maxBarcode); err != nil {
return 0, fmt.Errorf("barcode seed query failed: %w", err)
}
var hasTb int
if err := tx.QueryRow(`SELECT CASE WHEN OBJECT_ID(N'dbo.tbStokBarkodu', N'U') IS NULL THEN 0 ELSE 1 END`).Scan(&hasTb); err != nil {
return 0, fmt.Errorf("barcode seed object check failed: %w", err)
}
if hasTb == 1 {
var maxTb int64
maxTbQuery := `
SELECT ISNULL(MAX(v.BarcodeNum), 0)
FROM (
SELECT
CASE
WHEN LTRIM(RTRIM(ISNULL(sb.Barcode,''))) NOT LIKE '%[^0-9]%'
AND LEN(LTRIM(RTRIM(ISNULL(sb.Barcode,'')))) BETWEEN 1 AND 18
THEN CAST(LTRIM(RTRIM(ISNULL(sb.Barcode,''))) AS BIGINT)
ELSE NULL
END AS BarcodeNum
FROM dbo.tbStokBarkodu sb WITH (UPDLOCK, HOLDLOCK, TABLOCKX)
) v
WHERE v.BarcodeNum IS NOT NULL;
`
if err := tx.QueryRow(maxTbQuery).Scan(&maxTb); err != nil {
return 0, fmt.Errorf("barcode seed tbStokBarkodu query failed: %w", err)
}
if maxTb > maxBarcode {
maxBarcode = maxTb
}
}
if maxBarcode < 36999999 {
maxBarcode = 36999999
}
existsBarcodeQuery := `
SELECT CASE WHEN EXISTS (
SELECT 1
FROM dbo.prItemBarcode pb WITH (UPDLOCK, HOLDLOCK)
WHERE LTRIM(RTRIM(ISNULL(pb.Barcode,''))) = @p1
) THEN 1 ELSE 0 END;
`
existsBarcodeWithTbQuery := `
SELECT CASE WHEN EXISTS (
SELECT 1
FROM dbo.prItemBarcode pb WITH (UPDLOCK, HOLDLOCK)
WHERE LTRIM(RTRIM(ISNULL(pb.Barcode,''))) = @p1
) OR EXISTS (
SELECT 1
FROM dbo.tbStokBarkodu sb WITH (UPDLOCK, HOLDLOCK)
WHERE LTRIM(RTRIM(ISNULL(sb.Barcode,''))) = @p1
) THEN 1 ELSE 0 END;
`
hasVariantBarcodeQuery := `
SELECT CASE WHEN EXISTS (
SELECT 1
FROM dbo.prItemBarcode b WITH (UPDLOCK, HOLDLOCK)
WHERE b.ItemTypeCode = @p1
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemCode,'')))) = @p2
AND UPPER(LTRIM(RTRIM(ISNULL(b.ColorCode,'')))) = @p3
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim1Code,'')))) = @p4
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim2Code,'')))) = @p5
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim3Code,'')))) = @p6
) THEN 1 ELSE 0 END;
`
insertOneQuery := `
INSERT INTO dbo.prItemBarcode
(
Barcode,
BarcodeTypeCode,
ItemTypeCode,
ItemCode,
ColorCode,
ItemDim1Code,
ItemDim2Code,
ItemDim3Code,
UnitOfMeasureCode,
Qty,
CreatedUserName,
CreatedDate,
LastUpdatedUserName,
LastUpdatedDate,
RowGuid
)
SELECT
@p1,
'BAGGI3',
@p2,
@p3,
@p4,
@p5,
@p6,
@p7,
'AD',
1,
@p8,
GETDATE(),
@p8,
GETDATE(),
NEWID()
WHERE NOT EXISTS (
SELECT 1
FROM dbo.prItemBarcode b
WHERE b.ItemTypeCode = @p2
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemCode,'')))) = @p3
AND UPPER(LTRIM(RTRIM(ISNULL(b.ColorCode,'')))) = @p4
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim1Code,'')))) = @p5
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim2Code,'')))) = @p6
AND UPPER(LTRIM(RTRIM(ISNULL(b.ItemDim3Code,'')))) = @p7
);
`
var inserted int64
for _, t := range uniqueTargets {
if err := ensureTxStillActive(tx, "InsertItemBarcodesByTargetsTx/before_target"); err != nil {
return inserted, err
}
var hasVariant int
if err := tx.QueryRow(
hasVariantBarcodeQuery,
t.ItemTypeCode,
t.ItemCode,
t.ColorCode,
t.ItemDim1Code,
t.ItemDim2Code,
t.ItemDim3Code,
).Scan(&hasVariant); err != nil {
return inserted, fmt.Errorf("variant barcode exists check failed: %w", err)
}
if hasVariant == 1 {
continue
}
retry := 0
for {
retry++
if retry > 2000 {
return inserted, fmt.Errorf("barcode allocation exceeded retry limit item=%s color=%s dim1=%s", t.ItemCode, t.ColorCode, t.ItemDim1Code)
}
candidateNum := maxBarcode + 1
candidate := strconv.FormatInt(candidateNum, 10)
var exists int
if hasTb == 1 {
if err := tx.QueryRow(existsBarcodeWithTbQuery, candidate).Scan(&exists); err != nil {
return inserted, fmt.Errorf("barcode exists check(tb) failed: %w", err)
}
} else {
if err := tx.QueryRow(existsBarcodeQuery, candidate).Scan(&exists); err != nil {
return inserted, fmt.Errorf("barcode exists check failed: %w", err)
}
}
if exists == 1 {
maxBarcode = candidateNum
continue
}
res, err := tx.Exec(
insertOneQuery,
candidate,
t.ItemTypeCode,
t.ItemCode,
t.ColorCode,
t.ItemDim1Code,
t.ItemDim2Code,
t.ItemDim3Code,
username,
)
if err != nil {
if isDuplicateBarcodeInsertErr(err) {
maxBarcode = candidateNum
continue
}
return inserted, fmt.Errorf("insert item barcode failed item=%s color=%s dim1=%s duration_ms=%d: %w",
t.ItemCode, t.ColorCode, t.ItemDim1Code, time.Since(start).Milliseconds(), err)
}
affected, _ := res.RowsAffected()
if affected > 0 {
inserted += affected
maxBarcode = candidateNum
}
break
}
}
if txErr := ensureTxStillActive(tx, "InsertItemBarcodesByTargetsTx/after_batch"); txErr != nil {
return inserted, txErr
}
log.Printf("[InsertItemBarcodesByTargetsTx] targets=%d unique=%d inserted=%d duration_ms=%d",
len(targets), len(uniqueTargets), inserted, time.Since(start).Milliseconds())
return inserted, nil
}
func ensureTxStillActive(tx *sql.Tx, where string) error {
if tx == nil {
return fmt.Errorf("tx is nil at %s", where)
}
var tranCount int
if err := tx.QueryRow(`SELECT @@TRANCOUNT`).Scan(&tranCount); err != nil {
return fmt.Errorf("tx state query failed at %s: %w", where, err)
}
if tranCount <= 0 {
return fmt.Errorf("tx closed unexpectedly at %s (trancount=%d)", where, tranCount)
}
return nil
}
func isDuplicateBarcodeInsertErr(err error) bool {
if err == nil {
return false
}
msg := strings.ToLower(err.Error())
if !strings.Contains(msg, "duplicate key") {
return false
}
if strings.Contains(msg, "tbstokbarkodu") {
return true
}
if strings.Contains(msg, "pritembarcode") {
return true
}
return strings.Contains(msg, "unique")
}
func UpsertItemAttributesTx(tx *sql.Tx, attrs []models.OrderProductionItemAttributeRow, username string) (int64, error) {
start := time.Now()
if len(attrs) == 0 {
log.Printf("[UpsertItemAttributesTx] attrs=0 affected=0 duration_ms=0")
return 0, nil
}
// FK_prItemAttribute_ItemCode hatasini engellemek icin, attribute yazmadan once
// ilgili item kodlarinin cdItem tarafinda varligini transaction icinde garanti et.
seenCodes := make(map[string]struct{}, len(attrs))
for _, a := range attrs {
itemTypeCode := a.ItemTypeCode
if itemTypeCode <= 0 {
itemTypeCode = 1
}
itemCode := strings.ToUpper(strings.TrimSpace(a.ItemCode))
if itemCode == "" {
continue
}
key := NormalizeCdItemMapKey(int16(itemTypeCode), itemCode)
if _, ok := seenCodes[key]; ok {
continue
}
seenCodes[key] = struct{}{}
if err := ensureCdItemTx(tx, int16(itemTypeCode), itemCode, username, nil); err != nil {
return 0, fmt.Errorf("ensure cdItem before item attributes failed itemCode=%s: %w", itemCode, err)
}
}
// SQL Server parameter limiti (2100) nedeniyle batch'li set-based upsert kullanilir.
const chunkSize = 400 // 400 * 4 param + 1 username = 1601
var affected int64
for i := 0; i < len(attrs); i += chunkSize {
end := i + chunkSize
if end > len(attrs) {
end = len(attrs)
}
chunk := attrs[i:end]
values := make([]string, 0, len(chunk))
args := make([]any, 0, len(chunk)*4+1)
paramPos := 1
for _, a := range chunk {
values = append(values, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3))
args = append(args, a.ItemTypeCode, a.ItemCode, a.AttributeTypeCode, a.AttributeCode)
paramPos += 4
}
usernameParam := paramPos
args = append(args, username)
query := fmt.Sprintf(`
WITH src (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode) AS (
SELECT *
FROM (VALUES %s) AS v (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode)
)
UPDATE tgt
SET
tgt.AttributeCode = src.AttributeCode,
tgt.LastUpdatedUserName = @p%d,
tgt.LastUpdatedDate = GETDATE()
FROM dbo.prItemAttribute tgt
JOIN src
ON src.ItemTypeCode = tgt.ItemTypeCode
AND src.ItemCode = tgt.ItemCode
AND src.AttributeTypeCode = tgt.AttributeTypeCode;
WITH src (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode) AS (
SELECT *
FROM (VALUES %s) AS v (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode)
)
INSERT INTO dbo.prItemAttribute (
ItemTypeCode,
ItemCode,
AttributeTypeCode,
AttributeCode,
CreatedUserName,
CreatedDate,
LastUpdatedUserName,
LastUpdatedDate,
RowGuid
)
SELECT
src.ItemTypeCode,
src.ItemCode,
src.AttributeTypeCode,
src.AttributeCode,
@p%d,
GETDATE(),
@p%d,
GETDATE(),
NEWID()
FROM src
LEFT JOIN dbo.prItemAttribute tgt
ON src.ItemTypeCode = tgt.ItemTypeCode
AND src.ItemCode = tgt.ItemCode
AND src.AttributeTypeCode = tgt.AttributeTypeCode
WHERE tgt.ItemCode IS NULL;
`, strings.Join(values, ","), usernameParam, strings.Join(values, ","), usernameParam, usernameParam)
chunkStart := time.Now()
res, err := tx.Exec(query, args...)
if err != nil {
log.Printf("[UpsertItemAttributesTx] ERROR chunk=%d-%d err=%v", i, end, err)
return affected, fmt.Errorf("upsert item attributes chunk failed chunkStart=%d chunkEnd=%d duration_ms=%d: %w", i, end, time.Since(chunkStart).Milliseconds(), err)
}
chunkAffected, _ := res.RowsAffected()
affected += chunkAffected
log.Printf("[UpsertItemAttributesTx] chunk=%d-%d chunkAffected=%d cumulative=%d duration_ms=%d",
i, end, chunkAffected, affected, time.Since(chunkStart).Milliseconds())
}
log.Printf("[UpsertItemAttributesTx] attrs=%d affected=%d duration_ms=%d",
len(attrs), affected, time.Since(start).Milliseconds())
return affected, nil
}
func GetOrderProductionLookupOptions(mssql *sql.DB) (models.OrderProductionCdItemLookups, error) {
out := models.OrderProductionCdItemLookups{}
queryPairs := []struct {
Name string
Query string
Target *[]models.OrderProductionLookupOption
}{
{"ItemDimTypeCodes", `SELECT
CAST(t.ItemDimTypeCode AS NVARCHAR(50)) AS Code,
ISNULL(d.ItemDimTypeDescription, CAST(t.ItemDimTypeCode AS NVARCHAR(50))) AS [Description]
FROM dbo.bsItemDimType t WITH(NOLOCK)
LEFT JOIN dbo.bsItemDimTypeDesc d WITH(NOLOCK)
ON d.ItemDimTypeCode = t.ItemDimTypeCode
AND d.LangCode = 'TR'
WHERE ISNULL(t.IsBlocked, 0) = 0
ORDER BY t.ItemDimTypeCode`, &out.ItemDimTypeCodes},
{"ProductTypeCodes", `SELECT DISTINCT CAST(ProductTypeCode AS NVARCHAR(50)) AS Code, CAST(ProductTypeCode AS NVARCHAR(50)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ProductTypeCode IS NOT NULL ORDER BY Code`, &out.ProductTypeCodes},
{"ProductHierarchyIDs", `SELECT
CAST(h.ProductHierarchyID AS NVARCHAR(50)) AS Code,
LTRIM(RTRIM(
CONCAT(
CAST(ISNULL(h.ProductHierarchyLevelCode01, 0) AS NVARCHAR(50)),
CASE
WHEN ISNULL(d.ProductHierarchyLevelDescription, '') <> '' THEN CONCAT(' - ', d.ProductHierarchyLevelDescription)
ELSE ''
END
)
)) AS [Description]
FROM dbo.dfProductHierarchy h WITH(NOLOCK)
LEFT JOIN dbo.cdProductHierarchyLevelDesc d WITH(NOLOCK)
ON d.ProductHierarchyLevelCode = h.ProductHierarchyLevelCode01
AND d.LangCode = 'TR'
ORDER BY h.ProductHierarchyID`, &out.ProductHierarchyIDs},
{"UnitOfMeasureCode1List", `SELECT DISTINCT CAST(UnitOfMeasureCode1 AS NVARCHAR(50)) AS Code, CAST(UnitOfMeasureCode1 AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(UnitOfMeasureCode1 AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.UnitOfMeasureCode1List},
{"ItemAccountGrCodes", `SELECT DISTINCT CAST(ItemAccountGrCode AS NVARCHAR(50)) AS Code, CAST(ItemAccountGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ItemAccountGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemAccountGrCodes},
{"ItemTaxGrCodes", `SELECT DISTINCT CAST(ItemTaxGrCode AS NVARCHAR(50)) AS Code, CAST(ItemTaxGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ItemTaxGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemTaxGrCodes},
{"ItemPaymentPlanGrCodes", `SELECT DISTINCT CAST(ItemPaymentPlanGrCode AS NVARCHAR(50)) AS Code, CAST(ItemPaymentPlanGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ItemPaymentPlanGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemPaymentPlanGrCodes},
{"ItemDiscountGrCodes", `SELECT DISTINCT CAST(ItemDiscountGrCode AS NVARCHAR(50)) AS Code, CAST(ItemDiscountGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ItemDiscountGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemDiscountGrCodes},
{"ItemVendorGrCodes", `SELECT DISTINCT CAST(ItemVendorGrCode AS NVARCHAR(50)) AS Code, CAST(ItemVendorGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ItemVendorGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemVendorGrCodes},
{"PromotionGroupCodes", `SELECT DISTINCT CAST(PromotionGroupCode AS NVARCHAR(50)) AS Code, CAST(PromotionGroupCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(PromotionGroupCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.PromotionGroupCodes},
{"ProductCollectionGrCodes", `SELECT DISTINCT CAST(ProductCollectionGrCode AS NVARCHAR(50)) AS Code, CAST(ProductCollectionGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ProductCollectionGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ProductCollectionGrCodes},
{"StorePriceLevelCodes", `SELECT DISTINCT CAST(StorePriceLevelCode AS NVARCHAR(50)) AS Code, CAST(StorePriceLevelCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(StorePriceLevelCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.StorePriceLevelCodes},
{"PerceptionOfFashionCodes", `SELECT DISTINCT CAST(PerceptionOfFashionCode AS NVARCHAR(50)) AS Code, CAST(PerceptionOfFashionCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(PerceptionOfFashionCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.PerceptionOfFashionCodes},
{"CommercialRoleCodes", `SELECT DISTINCT CAST(CommercialRoleCode AS NVARCHAR(50)) AS Code, CAST(CommercialRoleCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(CommercialRoleCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.CommercialRoleCodes},
{"StoreCapacityLevelCodes", `SELECT DISTINCT CAST(StoreCapacityLevelCode AS NVARCHAR(50)) AS Code, CAST(StoreCapacityLevelCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(StoreCapacityLevelCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.StoreCapacityLevelCodes},
{"CustomsTariffNumbers", `SELECT DISTINCT CAST(CustomsTariffNumberCode AS NVARCHAR(50)) AS Code, CAST(CustomsTariffNumberCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(CustomsTariffNumberCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.CustomsTariffNumbers},
{"CompanyCodes", `SELECT DISTINCT CAST(CompanyCode AS NVARCHAR(50)) AS Code, CAST(CompanyCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(CompanyCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.CompanyCodes},
}
for _, pair := range queryPairs {
start := time.Now()
log.Printf("[GetOrderProductionLookupOptions] executing [%s]", pair.Name)
rows, err := mssql.Query(pair.Query)
if err != nil {
return out, fmt.Errorf("lookup query failed [%s]: %w", pair.Name, err)
}
list := make([]models.OrderProductionLookupOption, 0, 64)
for rows.Next() {
var item models.OrderProductionLookupOption
if err := rows.Scan(&item.Code, &item.Description); err != nil {
rows.Close()
return out, fmt.Errorf("lookup scan failed [%s]: %w", pair.Name, err)
}
item.Code = strings.TrimSpace(item.Code)
item.Description = strings.TrimSpace(item.Description)
list = append(list, item)
}
if err := rows.Err(); err != nil {
rows.Close()
return out, fmt.Errorf("lookup rows failed [%s]: %w", pair.Name, err)
}
rows.Close()
log.Printf("[GetOrderProductionLookupOptions] ok [%s] count=%d duration=%s", pair.Name, len(list), time.Since(start))
*pair.Target = list
}
return out, nil
}