Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -522,6 +522,7 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
|
||||
{"/api/order/get/{id}", "GET", "view", routes.GetOrderByIDHandler(mssql)},
|
||||
{"/api/orders/list", "GET", "view", routes.OrderListRoute(mssql)},
|
||||
{"/api/orders/production-list", "GET", "update", routes.OrderProductionListRoute(mssql)},
|
||||
{"/api/orders/production-items/cditem-lookups", "GET", "view", routes.OrderProductionCdItemLookupsRoute(mssql)},
|
||||
{"/api/orders/production-items/{id}", "GET", "view", routes.OrderProductionItemsRoute(mssql)},
|
||||
{"/api/orders/production-items/{id}/insert-missing", "POST", "update", routes.OrderProductionInsertMissingRoute(mssql)},
|
||||
{"/api/orders/production-items/{id}/validate", "POST", "update", routes.OrderProductionValidateRoute(mssql)},
|
||||
@@ -587,6 +588,11 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
|
||||
"order", "view",
|
||||
wrapV3(http.HandlerFunc(routes.GetProductSecondColorsHandler)),
|
||||
)
|
||||
bindV3(r, pgDB,
|
||||
"/api/product-attributes", "GET",
|
||||
"order", "view",
|
||||
wrapV3(http.HandlerFunc(routes.GetProductAttributesHandler)),
|
||||
)
|
||||
bindV3(r, pgDB,
|
||||
"/api/product-stock-query", "GET",
|
||||
"order", "view",
|
||||
|
||||
@@ -9,16 +9,72 @@ type OrderProductionUpdateLine struct {
|
||||
}
|
||||
|
||||
type OrderProductionUpdatePayload struct {
|
||||
Lines []OrderProductionUpdateLine `json:"lines"`
|
||||
InsertMissing bool `json:"insertMissing"`
|
||||
Lines []OrderProductionUpdateLine `json:"lines"`
|
||||
InsertMissing bool `json:"insertMissing"`
|
||||
CdItems []OrderProductionCdItemDraft `json:"cdItems"`
|
||||
ProductAttributes []OrderProductionItemAttributeRow `json:"productAttributes"`
|
||||
}
|
||||
|
||||
type OrderProductionMissingVariant struct {
|
||||
OrderLineID string `json:"OrderLineID"`
|
||||
ItemTypeCode int16 `json:"ItemTypeCode"`
|
||||
ItemCode string `json:"ItemCode"`
|
||||
ColorCode string `json:"ColorCode"`
|
||||
ItemDim1Code string `json:"ItemDim1Code"`
|
||||
ItemDim2Code string `json:"ItemDim2Code"`
|
||||
ItemDim3Code string `json:"ItemDim3Code"`
|
||||
OrderLineID string `json:"OrderLineID"`
|
||||
ItemTypeCode int16 `json:"ItemTypeCode"`
|
||||
ItemCode string `json:"ItemCode"`
|
||||
ColorCode string `json:"ColorCode"`
|
||||
ItemDim1Code string `json:"ItemDim1Code"`
|
||||
ItemDim2Code string `json:"ItemDim2Code"`
|
||||
ItemDim3Code string `json:"ItemDim3Code"`
|
||||
}
|
||||
|
||||
type OrderProductionCdItemDraft struct {
|
||||
ItemTypeCode int16 `json:"ItemTypeCode"`
|
||||
ItemCode string `json:"ItemCode"`
|
||||
ItemDimTypeCode *int16 `json:"ItemDimTypeCode"`
|
||||
ProductTypeCode *int16 `json:"ProductTypeCode"`
|
||||
ProductHierarchyID *int `json:"ProductHierarchyID"`
|
||||
UnitOfMeasureCode1 *string `json:"UnitOfMeasureCode1"`
|
||||
ItemAccountGrCode *string `json:"ItemAccountGrCode"`
|
||||
ItemTaxGrCode *string `json:"ItemTaxGrCode"`
|
||||
ItemPaymentPlanGrCode *string `json:"ItemPaymentPlanGrCode"`
|
||||
ItemDiscountGrCode *string `json:"ItemDiscountGrCode"`
|
||||
ItemVendorGrCode *string `json:"ItemVendorGrCode"`
|
||||
PromotionGroupCode *string `json:"PromotionGroupCode"`
|
||||
ProductCollectionGrCode *string `json:"ProductCollectionGrCode"`
|
||||
StorePriceLevelCode *string `json:"StorePriceLevelCode"`
|
||||
PerceptionOfFashionCode *string `json:"PerceptionOfFashionCode"`
|
||||
CommercialRoleCode *string `json:"CommercialRoleCode"`
|
||||
StoreCapacityLevelCode *string `json:"StoreCapacityLevelCode"`
|
||||
CustomsTariffNumberCode *string `json:"CustomsTariffNumberCode"`
|
||||
CompanyCode *string `json:"CompanyCode"`
|
||||
}
|
||||
|
||||
type OrderProductionLookupOption struct {
|
||||
Code string `json:"code"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type OrderProductionItemAttributeRow struct {
|
||||
ItemTypeCode int16 `json:"ItemTypeCode"`
|
||||
ItemCode string `json:"ItemCode"`
|
||||
AttributeTypeCode int `json:"AttributeTypeCode"`
|
||||
AttributeCode string `json:"AttributeCode"`
|
||||
}
|
||||
|
||||
type OrderProductionCdItemLookups struct {
|
||||
ItemDimTypeCodes []OrderProductionLookupOption `json:"itemDimTypeCodes"`
|
||||
ProductTypeCodes []OrderProductionLookupOption `json:"productTypeCodes"`
|
||||
ProductHierarchyIDs []OrderProductionLookupOption `json:"productHierarchyIDs"`
|
||||
UnitOfMeasureCode1List []OrderProductionLookupOption `json:"unitOfMeasureCode1List"`
|
||||
ItemAccountGrCodes []OrderProductionLookupOption `json:"itemAccountGrCodes"`
|
||||
ItemTaxGrCodes []OrderProductionLookupOption `json:"itemTaxGrCodes"`
|
||||
ItemPaymentPlanGrCodes []OrderProductionLookupOption `json:"itemPaymentPlanGrCodes"`
|
||||
ItemDiscountGrCodes []OrderProductionLookupOption `json:"itemDiscountGrCodes"`
|
||||
ItemVendorGrCodes []OrderProductionLookupOption `json:"itemVendorGrCodes"`
|
||||
PromotionGroupCodes []OrderProductionLookupOption `json:"promotionGroupCodes"`
|
||||
ProductCollectionGrCodes []OrderProductionLookupOption `json:"productCollectionGrCodes"`
|
||||
StorePriceLevelCodes []OrderProductionLookupOption `json:"storePriceLevelCodes"`
|
||||
PerceptionOfFashionCodes []OrderProductionLookupOption `json:"perceptionOfFashionCodes"`
|
||||
CommercialRoleCodes []OrderProductionLookupOption `json:"commercialRoleCodes"`
|
||||
StoreCapacityLevelCodes []OrderProductionLookupOption `json:"storeCapacityLevelCodes"`
|
||||
CustomsTariffNumbers []OrderProductionLookupOption `json:"customsTariffNumbers"`
|
||||
CompanyCodes []OrderProductionLookupOption `json:"companyCodes"`
|
||||
}
|
||||
|
||||
9
svc/models/productattributes.go
Normal file
9
svc/models/productattributes.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package models
|
||||
|
||||
type ProductAttributeOption struct {
|
||||
ItemTypeCode int16 `json:"item_type_code"`
|
||||
AttributeTypeCode int `json:"attribute_type_code"`
|
||||
AttributeTypeDescription string `json:"attribute_type_description"`
|
||||
AttributeCode string `json:"attribute_code"`
|
||||
AttributeDescription string `json:"attribute_description"`
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package models
|
||||
|
||||
type ProductSecondColor struct {
|
||||
ProductCode string `json:"product_code"`
|
||||
ColorCode string `json:"color_code"`
|
||||
ItemDim2Code string `json:"item_dim2_code"`
|
||||
ProductCode string `json:"product_code"`
|
||||
ColorCode string `json:"color_code"`
|
||||
ItemDim2Code string `json:"item_dim2_code"`
|
||||
ColorDescription string `json:"color_description"`
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package queries
|
||||
import (
|
||||
"database/sql"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"bssapp-backend/models"
|
||||
)
|
||||
@@ -74,10 +75,17 @@ INSERT INTO dbo.prItemVariant (
|
||||
ItemDim2Code,
|
||||
ItemDim3Code,
|
||||
PLU,
|
||||
IsSalesOrderClosed,
|
||||
IsPurchaseOrderClosed,
|
||||
IsLocked,
|
||||
IsBlocked,
|
||||
CreatedUserName,
|
||||
CreatedDate,
|
||||
LastUpdatedUserName,
|
||||
LastUpdatedDate
|
||||
LastUpdatedDate,
|
||||
RowGuid,
|
||||
UseInternet,
|
||||
IsStoreOrderClosed
|
||||
)
|
||||
SELECT
|
||||
m.ItemTypeCode,
|
||||
@@ -87,10 +95,17 @@ SELECT
|
||||
m.ItemDim2Code,
|
||||
m.ItemDim3Code,
|
||||
mp.BasePlu + ROW_NUMBER() OVER (ORDER BY m.ItemCode, m.ColorCode, m.ItemDim1Code, m.ItemDim2Code, m.ItemDim3Code),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
@p2,
|
||||
GETDATE(),
|
||||
@p2,
|
||||
GETDATE()
|
||||
GETDATE(),
|
||||
NEWID(),
|
||||
0,
|
||||
0
|
||||
FROM Missing m
|
||||
CROSS JOIN MaxPlu mp;
|
||||
`
|
||||
@@ -143,7 +158,12 @@ WHERE ItemTypeCode = @p1
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func InsertMissingVariantsTx(tx *sql.Tx, missing []models.OrderProductionMissingVariant, username string) (int64, error) {
|
||||
func InsertMissingVariantsTx(
|
||||
tx *sql.Tx,
|
||||
missing []models.OrderProductionMissingVariant,
|
||||
username string,
|
||||
cdItemByCode map[string]models.OrderProductionCdItemDraft,
|
||||
) (int64, error) {
|
||||
if len(missing) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
@@ -161,7 +181,16 @@ FROM dbo.prItemVariant WITH (UPDLOCK, HOLDLOCK)
|
||||
for i, v := range missing {
|
||||
itemKey := strconv.FormatInt(int64(v.ItemTypeCode), 10) + "|" + v.ItemCode
|
||||
if _, ok := ensuredItems[itemKey]; !ok {
|
||||
if err := ensureCdItemTx(tx, v.ItemTypeCode, v.ItemCode, username); err != nil {
|
||||
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{}{}
|
||||
@@ -187,14 +216,26 @@ INSERT INTO dbo.prItemVariant (
|
||||
ItemDim2Code,
|
||||
ItemDim3Code,
|
||||
PLU,
|
||||
IsSalesOrderClosed,
|
||||
IsPurchaseOrderClosed,
|
||||
IsLocked,
|
||||
IsBlocked,
|
||||
CreatedUserName,
|
||||
CreatedDate,
|
||||
LastUpdatedUserName,
|
||||
LastUpdatedDate
|
||||
LastUpdatedDate,
|
||||
RowGuid,
|
||||
UseInternet,
|
||||
IsStoreOrderClosed
|
||||
)
|
||||
VALUES (
|
||||
@p1, @p2, @p3, @p4, @p5, @p6,
|
||||
@p7, @p8, GETDATE(), @p8, GETDATE()
|
||||
@p7,
|
||||
0, 0, 0, 0,
|
||||
@p8, GETDATE(), @p8, GETDATE(),
|
||||
NEWID(),
|
||||
0,
|
||||
0
|
||||
);
|
||||
`, v.ItemTypeCode, v.ItemCode, v.ColorCode, v.ItemDim1Code, v.ItemDim2Code, v.ItemDim3Code, plu, username)
|
||||
if err != nil {
|
||||
@@ -207,7 +248,17 @@ VALUES (
|
||||
return inserted, nil
|
||||
}
|
||||
|
||||
func ensureCdItemTx(tx *sql.Tx, itemTypeCode int16, itemCode string, username string) error {
|
||||
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
|
||||
@@ -269,28 +320,90 @@ BEGIN
|
||||
INSERT INTO dbo.cdItem (
|
||||
ItemTypeCode, ItemCode,
|
||||
ItemDimTypeCode, ProductTypeCode, ProductHierarchyID,
|
||||
UnitOfMeasureCode1, UnitConvertRate, UnitConvertRateNotFixed,
|
||||
UnitOfMeasureCode1, UnitOfMeasureCode2, UnitConvertRate, UnitConvertRateNotFixed,
|
||||
UseInternet, UsePOS, UseStore, EnablePartnerCompanies, UseManufacturing, UseSerialNumber,
|
||||
GenerateOpticalDataMatrixCode, ByWeight, SupplyPeriod, GuaranteePeriod, ShelfLife, OrderLeadTime,
|
||||
IsFixedExpense, IsBlocked, IsLocked, LockedDate, IsSalesOrderClosed, IsPurchaseOrderClosed,
|
||||
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, IsUTSDeclaratedItem, IsStoreOrderClosed
|
||||
IsSubsequentDeliveryForR, IsSubsequentDeliveryForRI,
|
||||
IGACommissionGroup, UniFreeCommissionGroup, CustomsProductGroupCode, IsUTSDeclaratedItem, IsStoreOrderClosed
|
||||
)
|
||||
VALUES (
|
||||
@p1, @p2,
|
||||
2, 1, 2,
|
||||
'AD', 0, 0,
|
||||
0, 1, 1, 0, 1, 0,
|
||||
'AD', '', 0, 0,
|
||||
1, 1, 1, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, '1900-01-01', 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, 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 = COALESCE(NULLIF(@p8,''), ItemTaxGrCode),
|
||||
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
|
||||
}
|
||||
|
||||
@@ -317,3 +430,141 @@ WHERE OrderHeaderID = @p6 AND OrderLineID = @p7
|
||||
}
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
func UpsertItemAttributesTx(tx *sql.Tx, attrs []models.OrderProductionItemAttributeRow, username string) (int64, error) {
|
||||
if len(attrs) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var affected int64
|
||||
for _, a := range attrs {
|
||||
res, err := tx.Exec(`
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM dbo.prItemAttribute
|
||||
WHERE ItemTypeCode = @p1
|
||||
AND ItemCode = @p2
|
||||
AND AttributeTypeCode = @p3
|
||||
)
|
||||
BEGIN
|
||||
UPDATE dbo.prItemAttribute
|
||||
SET
|
||||
AttributeCode = @p4,
|
||||
LastUpdatedUserName = @p5,
|
||||
LastUpdatedDate = GETDATE()
|
||||
WHERE ItemTypeCode = @p1
|
||||
AND ItemCode = @p2
|
||||
AND AttributeTypeCode = @p3
|
||||
END
|
||||
ELSE
|
||||
BEGIN
|
||||
INSERT INTO dbo.prItemAttribute (
|
||||
ItemTypeCode,
|
||||
ItemCode,
|
||||
AttributeTypeCode,
|
||||
AttributeCode,
|
||||
CreatedUserName,
|
||||
CreatedDate,
|
||||
LastUpdatedUserName,
|
||||
LastUpdatedDate,
|
||||
RowGuid
|
||||
)
|
||||
VALUES (
|
||||
@p1,
|
||||
@p2,
|
||||
@p3,
|
||||
@p4,
|
||||
@p5,
|
||||
GETDATE(),
|
||||
@p5,
|
||||
GETDATE(),
|
||||
NEWID()
|
||||
)
|
||||
END
|
||||
`, a.ItemTypeCode, a.ItemCode, a.AttributeTypeCode, a.AttributeCode, username)
|
||||
if err != nil {
|
||||
return affected, err
|
||||
}
|
||||
if rows, err := res.RowsAffected(); err == nil {
|
||||
affected += rows
|
||||
}
|
||||
}
|
||||
return affected, nil
|
||||
}
|
||||
|
||||
func GetOrderProductionLookupOptions(mssql *sql.DB) (models.OrderProductionCdItemLookups, error) {
|
||||
out := models.OrderProductionCdItemLookups{}
|
||||
|
||||
queryPairs := []struct {
|
||||
Query string
|
||||
Target *[]models.OrderProductionLookupOption
|
||||
}{
|
||||
{`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},
|
||||
{`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},
|
||||
{`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},
|
||||
{`SELECT DISTINCT CAST(UnitOfMeasureCode1 AS NVARCHAR(50)) AS Code, CAST(UnitOfMeasureCode1 AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(UnitOfMeasureCode1,'') <> '' ORDER BY Code`, &out.UnitOfMeasureCode1List},
|
||||
{`SELECT DISTINCT CAST(ItemAccountGrCode AS NVARCHAR(50)) AS Code, CAST(ItemAccountGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ItemAccountGrCode,'') <> '' ORDER BY Code`, &out.ItemAccountGrCodes},
|
||||
{`SELECT DISTINCT CAST(ItemTaxGrCode AS NVARCHAR(50)) AS Code, CAST(ItemTaxGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ItemTaxGrCode,'') <> '' ORDER BY Code`, &out.ItemTaxGrCodes},
|
||||
{`SELECT DISTINCT CAST(ItemPaymentPlanGrCode AS NVARCHAR(50)) AS Code, CAST(ItemPaymentPlanGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ItemPaymentPlanGrCode,'') <> '' ORDER BY Code`, &out.ItemPaymentPlanGrCodes},
|
||||
{`SELECT DISTINCT CAST(ItemDiscountGrCode AS NVARCHAR(50)) AS Code, CAST(ItemDiscountGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ItemDiscountGrCode,'') <> '' ORDER BY Code`, &out.ItemDiscountGrCodes},
|
||||
{`SELECT DISTINCT CAST(ItemVendorGrCode AS NVARCHAR(50)) AS Code, CAST(ItemVendorGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ItemVendorGrCode,'') <> '' ORDER BY Code`, &out.ItemVendorGrCodes},
|
||||
{`SELECT DISTINCT CAST(PromotionGroupCode AS NVARCHAR(50)) AS Code, CAST(PromotionGroupCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(PromotionGroupCode,'') <> '' ORDER BY Code`, &out.PromotionGroupCodes},
|
||||
{`SELECT DISTINCT CAST(ProductCollectionGrCode AS NVARCHAR(50)) AS Code, CAST(ProductCollectionGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ProductCollectionGrCode,'') <> '' ORDER BY Code`, &out.ProductCollectionGrCodes},
|
||||
{`SELECT DISTINCT CAST(StorePriceLevelCode AS NVARCHAR(50)) AS Code, CAST(StorePriceLevelCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(StorePriceLevelCode,'') <> '' ORDER BY Code`, &out.StorePriceLevelCodes},
|
||||
{`SELECT DISTINCT CAST(PerceptionOfFashionCode AS NVARCHAR(50)) AS Code, CAST(PerceptionOfFashionCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(PerceptionOfFashionCode,'') <> '' ORDER BY Code`, &out.PerceptionOfFashionCodes},
|
||||
{`SELECT DISTINCT CAST(CommercialRoleCode AS NVARCHAR(50)) AS Code, CAST(CommercialRoleCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(CommercialRoleCode,'') <> '' ORDER BY Code`, &out.CommercialRoleCodes},
|
||||
{`SELECT DISTINCT CAST(StoreCapacityLevelCode AS NVARCHAR(50)) AS Code, CAST(StoreCapacityLevelCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(StoreCapacityLevelCode,'') <> '' ORDER BY Code`, &out.StoreCapacityLevelCodes},
|
||||
{`SELECT DISTINCT CAST(CustomsTariffNumberCode AS NVARCHAR(50)) AS Code, CAST(CustomsTariffNumberCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(CustomsTariffNumberCode,'') <> '' ORDER BY Code`, &out.CustomsTariffNumbers},
|
||||
{`SELECT DISTINCT CAST(CompanyCode AS NVARCHAR(50)) AS Code, CAST(CompanyCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(CompanyCode,'') <> '' ORDER BY Code`, &out.CompanyCodes},
|
||||
}
|
||||
|
||||
for _, pair := range queryPairs {
|
||||
rows, err := mssql.Query(pair.Query)
|
||||
if err != nil {
|
||||
return out, 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, 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, err
|
||||
}
|
||||
rows.Close()
|
||||
*pair.Target = list
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
42
svc/queries/productattributes.go
Normal file
42
svc/queries/productattributes.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package queries
|
||||
|
||||
const GetProductAttributes = `
|
||||
;WITH TypeDesc AS (
|
||||
SELECT
|
||||
t.ItemTypeCode,
|
||||
t.AttributeTypeCode,
|
||||
ISNULL(t.AttributeTypeDescription, CAST(t.AttributeTypeCode AS NVARCHAR(30))) AS AttributeTypeDescription
|
||||
FROM dbo.cdItemAttributeTypeDesc AS t WITH(NOLOCK)
|
||||
WHERE t.ItemTypeCode = @p1
|
||||
AND t.LangCode = 'TR'
|
||||
),
|
||||
Attr AS (
|
||||
SELECT
|
||||
a.ItemTypeCode,
|
||||
a.AttributeTypeCode,
|
||||
ISNULL(a.AttributeCode, '') AS AttributeCode,
|
||||
ISNULL(d.AttributeDescription, ISNULL(a.AttributeCode, '')) AS AttributeDescription
|
||||
FROM dbo.cdItemAttribute AS a WITH(NOLOCK)
|
||||
LEFT JOIN dbo.cdItemAttributeDesc AS d WITH(NOLOCK)
|
||||
ON d.ItemTypeCode = a.ItemTypeCode
|
||||
AND d.AttributeTypeCode = a.AttributeTypeCode
|
||||
AND d.AttributeCode = a.AttributeCode
|
||||
AND d.LangCode = 'TR'
|
||||
WHERE a.ItemTypeCode = @p1
|
||||
AND ISNULL(a.IsBlocked, 0) = 0
|
||||
),
|
||||
SELECT
|
||||
a.ItemTypeCode,
|
||||
a.AttributeTypeCode,
|
||||
ISNULL(NULLIF(td.AttributeTypeDescription, ''), CAST(a.AttributeTypeCode AS NVARCHAR(30))) AS AttributeTypeDescription,
|
||||
a.AttributeCode,
|
||||
a.AttributeDescription
|
||||
FROM Attr a
|
||||
LEFT JOIN TypeDesc td
|
||||
ON td.ItemTypeCode = a.ItemTypeCode
|
||||
AND td.AttributeTypeCode = a.AttributeTypeCode
|
||||
ORDER BY
|
||||
a.AttributeTypeCode,
|
||||
CASE WHEN a.AttributeCode = '-' THEN 0 ELSE 1 END,
|
||||
a.AttributeCode;
|
||||
`
|
||||
@@ -4,7 +4,8 @@ const GetProductSecondColors = `
|
||||
SELECT DISTINCT
|
||||
Product.ProductCode,
|
||||
ISNULL(prItemVariant.ColorCode, '') AS ColorCode,
|
||||
ISNULL(prItemVariant.ItemDim2Code, '') AS ItemDim2Code
|
||||
ISNULL(prItemVariant.ItemDim2Code, '') AS ItemDim2Code,
|
||||
ISNULL(ColorDesc.ColorDescription, '') AS ColorDescription
|
||||
FROM prItemVariant WITH(NOLOCK)
|
||||
INNER JOIN ProductFilterWithDescription('TR') AS Product
|
||||
ON prItemVariant.ItemCode = Product.ProductCode
|
||||
@@ -14,5 +15,10 @@ FROM prItemVariant WITH(NOLOCK)
|
||||
WHERE Product.ProductCode = @ProductCode
|
||||
AND prItemVariant.ColorCode = @ColorCode
|
||||
AND ISNULL(prItemVariant.ItemDim2Code, '') <> ''
|
||||
GROUP BY Product.ProductCode, prItemVariant.ItemDim2Code, prItemVariant.ColorCode
|
||||
GROUP BY
|
||||
Product.ProductCode,
|
||||
prItemVariant.ItemDim2Code,
|
||||
prItemVariant.ColorCode,
|
||||
ColorDesc.ColorDescription
|
||||
ORDER BY prItemVariant.ItemDim2Code
|
||||
`
|
||||
|
||||
@@ -1597,6 +1597,17 @@ func renderOrderGrid(pdf *gofpdf.Fpdf, header *OrderHeader, rows []PdfRow, hasVa
|
||||
layout := newPdfLayout(pdf)
|
||||
catSizes := buildCategorySizeMap(rows)
|
||||
|
||||
normalizeYetiskinGarsonTokenGo := func(v string) string {
|
||||
s := strings.ToUpper(strings.TrimSpace(v))
|
||||
if strings.Contains(s, "GARSON") {
|
||||
return "GARSON"
|
||||
}
|
||||
if strings.Contains(s, "YETISKIN") || strings.Contains(s, "YETİSKİN") {
|
||||
return "YETISKIN"
|
||||
}
|
||||
return "GENEL"
|
||||
}
|
||||
|
||||
// Grup: ÜRÜN ANA GRUBU
|
||||
type group struct {
|
||||
Name string
|
||||
@@ -1609,15 +1620,19 @@ func renderOrderGrid(pdf *gofpdf.Fpdf, header *OrderHeader, rows []PdfRow, hasVa
|
||||
var order []string
|
||||
|
||||
for _, r := range rows {
|
||||
name := strings.TrimSpace(r.GroupMain)
|
||||
if name == "" {
|
||||
name = "GENEL"
|
||||
ana := strings.TrimSpace(r.GroupMain)
|
||||
if ana == "" {
|
||||
ana = "GENEL"
|
||||
}
|
||||
g, ok := groups[name]
|
||||
yg := normalizeYetiskinGarsonTokenGo(r.YetiskinGarson)
|
||||
name := strings.TrimSpace(fmt.Sprintf("%s %s", yg, ana))
|
||||
groupKey := fmt.Sprintf("%s::%s", yg, ana)
|
||||
|
||||
g, ok := groups[groupKey]
|
||||
if !ok {
|
||||
g = &group{Name: name}
|
||||
groups[name] = g
|
||||
order = append(order, name)
|
||||
groups[groupKey] = g
|
||||
order = append(order, groupKey)
|
||||
}
|
||||
g.Rows = append(g.Rows, r)
|
||||
g.Adet += r.TotalQty
|
||||
@@ -1673,8 +1688,8 @@ func renderOrderGrid(pdf *gofpdf.Fpdf, header *OrderHeader, rows []PdfRow, hasVa
|
||||
newPage(firstPage, true)
|
||||
firstPage = false
|
||||
|
||||
for _, name := range order {
|
||||
g := groups[name]
|
||||
for _, key := range order {
|
||||
g := groups[key]
|
||||
|
||||
for _, row := range g.Rows {
|
||||
rh := calcRowHeight(pdf, layout, row)
|
||||
|
||||
@@ -9,12 +9,15 @@ import (
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
mssql "github.com/microsoft/go-mssqldb"
|
||||
)
|
||||
|
||||
var baggiModelCodeRegex = regexp.MustCompile(`^[A-Z][0-9]{3}-[A-Z]{3}[0-9]{5}$`)
|
||||
|
||||
// ======================================================
|
||||
// 📌 OrderProductionItemsRoute — U ürün satırları
|
||||
// ======================================================
|
||||
@@ -73,6 +76,23 @@ func OrderProductionItemsRoute(mssql *sql.DB) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func OrderProductionCdItemLookupsRoute(mssql *sql.DB) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
lookups, err := queries.GetOrderProductionLookupOptions(mssql)
|
||||
if err != nil {
|
||||
log.Printf("[OrderProductionCdItemLookupsRoute] lookup error: %v", err)
|
||||
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(w).Encode(lookups); err != nil {
|
||||
log.Printf("[OrderProductionCdItemLookupsRoute] encode error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
// 📌 OrderProductionInsertMissingRoute — eksik varyantları ekler
|
||||
// ======================================================
|
||||
@@ -208,13 +228,24 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
|
||||
|
||||
var inserted int64
|
||||
if payload.InsertMissing {
|
||||
inserted, err = queries.InsertMissingVariantsTx(tx, missing, username)
|
||||
cdItemByCode := buildCdItemDraftMap(payload.CdItems)
|
||||
inserted, err = queries.InsertMissingVariantsTx(tx, missing, username, cdItemByCode)
|
||||
if err != nil {
|
||||
writeDBError(w, http.StatusInternalServerError, "insert_missing_variants", id, username, len(missing), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateProductAttributes(payload.ProductAttributes); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
attributeAffected, err := queries.UpsertItemAttributesTx(tx, payload.ProductAttributes, username)
|
||||
if err != nil {
|
||||
writeDBError(w, http.StatusInternalServerError, "upsert_item_attributes", id, username, len(payload.ProductAttributes), err)
|
||||
return
|
||||
}
|
||||
|
||||
updated, err := queries.UpdateOrderLinesTx(tx, id, payload.Lines, username)
|
||||
if err != nil {
|
||||
writeDBError(w, http.StatusInternalServerError, "update_order_lines", id, username, len(payload.Lines), err)
|
||||
@@ -227,8 +258,9 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
|
||||
}
|
||||
|
||||
resp := map[string]any{
|
||||
"updated": updated,
|
||||
"inserted": inserted,
|
||||
"updated": updated,
|
||||
"inserted": inserted,
|
||||
"attributeUpserted": attributeAffected,
|
||||
}
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
log.Printf("❌ encode error: %v", err)
|
||||
@@ -236,6 +268,44 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func validateProductAttributes(attrs []models.OrderProductionItemAttributeRow) error {
|
||||
for _, a := range attrs {
|
||||
if strings.TrimSpace(a.ItemCode) == "" {
|
||||
return errors.New("Urun ozellikleri icin ItemCode zorunlu")
|
||||
}
|
||||
if !baggiModelCodeRegex.MatchString(strings.ToUpper(strings.TrimSpace(a.ItemCode))) {
|
||||
return errors.New("Girdiginiz kod BAGGI kod sistemine uyumlu degil. Format: X999-XXX99999")
|
||||
}
|
||||
if a.ItemTypeCode <= 0 {
|
||||
return errors.New("Urun ozellikleri icin ItemTypeCode zorunlu")
|
||||
}
|
||||
if a.AttributeTypeCode <= 0 {
|
||||
return errors.New("Urun ozellikleri icin AttributeTypeCode zorunlu")
|
||||
}
|
||||
if strings.TrimSpace(a.AttributeCode) == "" {
|
||||
return errors.New("Urun ozellikleri icin AttributeCode zorunlu")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildCdItemDraftMap(list []models.OrderProductionCdItemDraft) map[string]models.OrderProductionCdItemDraft {
|
||||
out := make(map[string]models.OrderProductionCdItemDraft, len(list))
|
||||
for _, item := range list {
|
||||
code := strings.ToUpper(strings.TrimSpace(item.ItemCode))
|
||||
if code == "" {
|
||||
continue
|
||||
}
|
||||
item.ItemCode = code
|
||||
if item.ItemTypeCode == 0 {
|
||||
item.ItemTypeCode = 1
|
||||
}
|
||||
key := queries.NormalizeCdItemMapKey(item.ItemTypeCode, item.ItemCode)
|
||||
out[key] = item
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func buildMissingVariants(mssql *sql.DB, orderHeaderID string, lines []models.OrderProductionUpdateLine) ([]models.OrderProductionMissingVariant, error) {
|
||||
missing := make([]models.OrderProductionMissingVariant, 0)
|
||||
|
||||
@@ -279,9 +349,13 @@ func validateUpdateLines(lines []models.OrderProductionUpdateLine) error {
|
||||
if strings.TrimSpace(line.OrderLineID) == "" {
|
||||
return errors.New("OrderLineID zorunlu")
|
||||
}
|
||||
if strings.TrimSpace(line.NewItemCode) == "" {
|
||||
code := strings.ToUpper(strings.TrimSpace(line.NewItemCode))
|
||||
if code == "" {
|
||||
return errors.New("Yeni urun kodu zorunlu")
|
||||
}
|
||||
if !baggiModelCodeRegex.MatchString(code) {
|
||||
return errors.New("Girdiginiz kod BAGGI kod sistemine uyumlu degil. Format: X999-XXX99999")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
54
svc/routes/productattributes.go
Normal file
54
svc/routes/productattributes.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"bssapp-backend/auth"
|
||||
"bssapp-backend/db"
|
||||
"bssapp-backend/models"
|
||||
"bssapp-backend/queries"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func GetProductAttributesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
claims, ok := auth.GetClaimsFromContext(r.Context())
|
||||
if !ok || claims == nil {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
itemTypeCode := int16(1)
|
||||
if raw := r.URL.Query().Get("itemTypeCode"); raw != "" {
|
||||
v, err := strconv.Atoi(raw)
|
||||
if err != nil || v <= 0 {
|
||||
http.Error(w, "itemTypeCode gecersiz", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
itemTypeCode = int16(v)
|
||||
}
|
||||
|
||||
rows, err := db.MssqlDB.Query(queries.GetProductAttributes, itemTypeCode)
|
||||
if err != nil {
|
||||
http.Error(w, "Product attributes alinamadi: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
list := make([]models.ProductAttributeOption, 0, 256)
|
||||
for rows.Next() {
|
||||
var x models.ProductAttributeOption
|
||||
if err := rows.Scan(
|
||||
&x.ItemTypeCode,
|
||||
&x.AttributeTypeCode,
|
||||
&x.AttributeTypeDescription,
|
||||
&x.AttributeCode,
|
||||
&x.AttributeDescription,
|
||||
); err != nil {
|
||||
continue
|
||||
}
|
||||
list = append(list, x)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
_ = json.NewEncoder(w).Encode(list)
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func GetProductSecondColorsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var list []models.ProductSecondColor
|
||||
for rows.Next() {
|
||||
var c models.ProductSecondColor
|
||||
if err := rows.Scan(&c.ProductCode, &c.ColorCode, &c.ItemDim2Code); err != nil {
|
||||
if err := rows.Scan(&c.ProductCode, &c.ColorCode, &c.ItemDim2Code, &c.ColorDescription); err != nil {
|
||||
log.Println("⚠️ Satır okunamadı:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user