stock update
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"nearle/models"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
@@ -1008,6 +1009,48 @@ func (r *orderRepository) GetOrderDetails(orderHeaderID int) ([]models.OrderDeta
|
||||
func (r *orderRepository) UpdateOrder(order *models.Orders) error {
|
||||
tx := r.db.Begin()
|
||||
|
||||
// Handle stock restoration on order cancellation
|
||||
var existingOrder models.Orders
|
||||
if err := tx.Where("orderheaderid = ?", order.Orderheaderid).First(&existingOrder).Error; err == nil {
|
||||
newStatus := strings.ToLower(strings.TrimSpace(order.Orderstatus))
|
||||
oldStatus := strings.ToLower(strings.TrimSpace(existingOrder.Orderstatus))
|
||||
|
||||
if newStatus == "cancelled" && oldStatus != "cancelled" {
|
||||
var items []models.OrderDetail
|
||||
if err := tx.Table("orderdetails").Where("orderheaderid = ?", order.Orderheaderid).Find(&items).Error; err == nil {
|
||||
for _, item := range items {
|
||||
itemLocID := item.Locationid
|
||||
if itemLocID == 0 {
|
||||
itemLocID = existingOrder.Locationid
|
||||
}
|
||||
qty := int(item.Orderqty)
|
||||
if qty <= 0 {
|
||||
qty = 1
|
||||
}
|
||||
|
||||
restoredStock := models.Productstock{
|
||||
Tenantid: existingOrder.Tenantid,
|
||||
Stockdate: time.Now(),
|
||||
Locationid: itemLocID,
|
||||
Productid: item.Productid,
|
||||
Quantity: qty,
|
||||
Stocktype: "in",
|
||||
Status: "Active",
|
||||
}
|
||||
if err := tx.Table("productstocks").Create(&restoredStock).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
||||
// Update productlocation status back to available if stock is restored
|
||||
tx.Table("productlocations").
|
||||
Where("productid = ? AND tenantid = ? AND locationid = ?", item.Productid, existingOrder.Tenantid, itemLocID).
|
||||
Update("status", "available")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Where("orderheaderid = ?", order.Orderheaderid).Updates(order).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
@@ -1082,6 +1125,50 @@ func (r *orderRepository) updateSeqno(tid int, prefix string) error {
|
||||
func (r *orderRepository) CreateOrder(data models.Orders) (models.Orders, error) {
|
||||
tx := r.db.Begin()
|
||||
|
||||
locID := data.Locationid
|
||||
if locID == 0 {
|
||||
locID = data.Applocationid
|
||||
}
|
||||
|
||||
// 🛠️ Step 1: Pre-validate stock availability for all items before placing order
|
||||
for _, item := range data.Items {
|
||||
itemLocID := item.Locationid
|
||||
if itemLocID == 0 {
|
||||
itemLocID = locID
|
||||
}
|
||||
|
||||
requestedQty := int(item.Orderqty)
|
||||
if requestedQty <= 0 {
|
||||
requestedQty = 1
|
||||
}
|
||||
|
||||
var availableStock int
|
||||
stockQuery := `
|
||||
SELECT COALESCE(
|
||||
SUM(CASE WHEN LOWER(stocktype) = 'in' THEN quantity ELSE 0 END) -
|
||||
SUM(CASE WHEN LOWER(stocktype) = 'out' THEN quantity ELSE 0 END),
|
||||
0
|
||||
)
|
||||
FROM productstocks
|
||||
WHERE productid = ? AND tenantid = ? AND locationid = ?
|
||||
`
|
||||
if err := tx.Raw(stockQuery, item.Productid, data.Tenantid, itemLocID).Scan(&availableStock).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return models.Orders{}, fmt.Errorf("failed to verify stock for product %d: %w", item.Productid, err)
|
||||
}
|
||||
|
||||
// If stock tracking exists and available stock is less than requested quantity, block order placement
|
||||
if availableStock < requestedQty {
|
||||
tx.Rollback()
|
||||
pName := item.Productname
|
||||
if pName == "" {
|
||||
pName = fmt.Sprintf("ID %d", item.Productid)
|
||||
}
|
||||
return models.Orders{}, fmt.Errorf("insufficient stock for product '%s': requested %d, available %d", pName, requestedQty, availableStock)
|
||||
}
|
||||
}
|
||||
|
||||
// 🛠️ Step 2: Create Order Header
|
||||
data.Orderid = r.getSequenceno(data.Tenantid, "ORD")
|
||||
|
||||
if err := tx.Create(&data).Error; err != nil {
|
||||
@@ -1089,22 +1176,32 @@ func (r *orderRepository) CreateOrder(data models.Orders) (models.Orders, error)
|
||||
return models.Orders{}, err
|
||||
}
|
||||
|
||||
// 🛠️ Step 3: Insert Order Details & Record "out" stock deduction
|
||||
for _, item := range data.Items {
|
||||
item.Orderheaderid = data.Orderheaderid
|
||||
item.Tenantid = data.Tenantid
|
||||
item.Locationid = data.Locationid
|
||||
itemLocID := item.Locationid
|
||||
if itemLocID == 0 {
|
||||
itemLocID = locID
|
||||
}
|
||||
item.Locationid = itemLocID
|
||||
|
||||
if err := tx.Table("orderdetails").Create(&item).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return models.Orders{}, err
|
||||
}
|
||||
|
||||
qty := int(item.Orderqty)
|
||||
if qty <= 0 {
|
||||
qty = 1
|
||||
}
|
||||
|
||||
stock := models.Productstock{
|
||||
Tenantid: data.Tenantid,
|
||||
Stockdate: time.Now(),
|
||||
Locationid: data.Locationid,
|
||||
Locationid: itemLocID,
|
||||
Productid: item.Productid,
|
||||
Quantity: int(item.Orderqty),
|
||||
Quantity: qty,
|
||||
Stocktype: "out",
|
||||
Status: "Active",
|
||||
}
|
||||
@@ -1112,6 +1209,25 @@ func (r *orderRepository) CreateOrder(data models.Orders) (models.Orders, error)
|
||||
tx.Rollback()
|
||||
return models.Orders{}, err
|
||||
}
|
||||
|
||||
// Update productlocation status to 'outofstock' if remaining stock drops to 0 or below
|
||||
var remainingStock int
|
||||
remStockQuery := `
|
||||
SELECT COALESCE(
|
||||
SUM(CASE WHEN LOWER(stocktype) = 'in' THEN quantity ELSE 0 END) -
|
||||
SUM(CASE WHEN LOWER(stocktype) = 'out' THEN quantity ELSE 0 END),
|
||||
0
|
||||
)
|
||||
FROM productstocks
|
||||
WHERE productid = ? AND tenantid = ? AND locationid = ?
|
||||
`
|
||||
if err := tx.Raw(remStockQuery, item.Productid, data.Tenantid, itemLocID).Scan(&remainingStock).Error; err == nil {
|
||||
if remainingStock <= 0 {
|
||||
tx.Table("productlocations").
|
||||
Where("productid = ? AND tenantid = ? AND locationid = ?", item.Productid, data.Tenantid, itemLocID).
|
||||
Update("status", "outofstock")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.updateSeqno(data.Tenantid, "ORD"); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user