2026-07-15 18:51:09 +06:00
using Ease.NetCore.DataAccess ;
using Ease.NetCore.DataAccess.SQL ;
using Microsoft.Data.SqlClient ;
using Microsoft.Extensions.Options ;
2026-07-16 18:30:18 +06:00
using OnlineSalesAutoCrop.CoreAPI.Models ;
2026-07-15 18:51:09 +06:00
using OnlineSalesAutoCrop.CoreAPI.Models.Global ;
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp ;
2026-07-18 18:55:29 +06:00
using OnlineSalesAutoCrop.CoreAPI.Models.Responses ;
2026-07-15 18:51:09 +06:00
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp ;
2026-07-26 18:18:02 +06:00
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations ;
2026-07-15 18:51:09 +06:00
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.MobileApp ;
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems ;
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Linq ;
2026-07-20 18:30:13 +06:00
using System.Threading ;
2026-07-15 18:51:09 +06:00
using System.Threading.Tasks ;
namespace OnlineSalesAutoCrop.CoreAPI.Services.Services.MobileApp ;
public class OrderService : IOrderService
{
private readonly AppSettings _settings ;
private readonly IUserService _userService ;
private readonly IMobileMasterDataService _masterService ;
2026-07-26 18:18:02 +06:00
private readonly IIntegrationHttpService _httpService ;
2026-07-15 18:51:09 +06:00
2026-07-26 18:18:02 +06:00
public OrderService ( IOptions < AppSettings > options , IUserService userService , IMobileMasterDataService masterService ,
IIntegrationHttpService httpService )
2026-07-15 18:51:09 +06:00
{
_settings = options . Value ;
_userService = userService ;
_masterService = masterService ;
2026-07-26 18:18:02 +06:00
_httpService = httpService ;
2026-07-15 18:51:09 +06:00
}
2026-07-16 18:30:18 +06:00
public async Task < SaveOrderResponse > SaveOrderAsync ( SaveOrderRequest request , int userId )
2026-07-15 18:51:09 +06:00
{
SaveOrderResponse response = new ( ) ;
2026-07-16 18:30:18 +06:00
2026-07-15 18:51:09 +06:00
try
{
2026-07-16 18:30:18 +06:00
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
// 1. Role - fetched using the claims-resolved UserId
UserRoleDto ? userRole = await GetUserRoleAsync ( tc , userId ) ;
if ( userRole is null )
throw new Exception ( $"User id '{userId}' was not found." ) ;
if ( ! IsPermissiontoModify ( request . OrderStatus , userRole . RoleId ) )
{
throw new Exception ( "You are not permitted to submit of modify this order" ) ;
}
var existingOrder = await GetExistingOrderIdAsync ( tc , request . UUID ) ;
2026-07-18 18:55:29 +06:00
request . OrderId = ( existingOrder ! = null & & existingOrder . OrderId > 0 ) ? existingOrder . OrderId : 0 ;
if ( existingOrder is not null & & existingOrder . OrderId > 0 & &
( existingOrder . OrderStatus = = OrderStatusEnum . Approved | |
existingOrder . OrderStatus = = OrderStatusEnum . CancelledByApprover | |
existingOrder . OrderStatus = = OrderStatusEnum . CancelledByValidator ) )
{
throw new Exception ( $"Order with UUID '{request.UUID}' has already been {existingOrder.OrderStatus.ToString()} and cannot be modified." ) ;
}
2026-07-16 18:30:18 +06:00
foreach ( var item in request . Items )
{
2026-08-12 18:29:10 +06:00
if ( ! item . IsFocItem & & item . UnitPrice < = 0 )
{
throw new Exception ( string . Format ( "No base price is available for this material of this customer distributor channel.Material:{0}-{1}" , item . MaterialCode , item . MaterialName ) ) ;
}
2026-07-16 18:30:18 +06:00
item . ItemId = 0 ;
item . OrderId = request . OrderId ;
}
2026-08-12 18:29:10 +06:00
var materialStock = await _httpService . GetMaterialStockAsync ( request . PlantCode ) ;
if ( materialStock is null | | materialStock ? . Count = = 0 )
{
throw new Exception ( $"Material Stocks not found against this Plant Code-{request.PlantCode}" ) ;
}
foreach ( var item in request . Items )
{
decimal currentStock = materialStock . FirstOrDefault ( x = > x . MaterialCode = = item . MaterialCode ) ? . AvailableStock ? ? 0 ;
if ( currentStock < item . ApprovedQuantity )
{
throw new Exception ( $"Insufficient stock is available for Material Code '{item.MaterialCode}' in Plant Code '{request.PlantCode}'." ) ;
}
}
2026-07-16 18:30:18 +06:00
// 2. Insert vs update decision
bool isUpdate = existingOrder ! = null & & existingOrder . OrderId > 0 ;
2026-07-15 18:51:09 +06:00
2026-07-16 18:30:18 +06:00
// 3. Reference data - SPs only fetch, every pass/fail call happens here
CustomerLookupDto ? customer = await GetCustomerAsync ( tc , request . CustomerCode ) ;
if ( customer is null )
throw new Exception ( $"Customer code '{request.CustomerCode}' does not exist." ) ;
2026-07-15 18:51:09 +06:00
2026-07-16 18:30:18 +06:00
request . CustomerId = customer . CustomerId ;
2026-07-15 18:51:09 +06:00
2026-07-16 18:30:18 +06:00
PaymentTermLookupDto ? paymentTerm = await GetPaymentTermAsync ( tc , request . PaymentTermCode , request . SalesOrgCode ) ;
if ( paymentTerm is null )
throw new Exception ( $"Payment term code '{request.PaymentTermCode}' does not exist for sales org '{request.SalesOrgCode}'." ) ;
2026-07-15 18:51:09 +06:00
2026-07-16 18:30:18 +06:00
DiscountLookupDto ? discount = await GetDiscountAsync ( tc , request . DiscountCode , request . SalesOrgCode ) ;
if ( discount is null )
throw new Exception ( $"Discount code '{request.DiscountCode}' does not exist." ) ;
bool focCodeExists = await CheckFocCodeExistsAsync ( tc , request . FocCode , request . SalesOrgCode ) ;
if ( ! focCodeExists )
throw new Exception ( $"FOC code '{request.FocCode}' does not exist." ) ;
if ( request . Items is null | | request . Items . Count = = 0 )
throw new Exception ( "Order must contain at least one item." ) ;
Dictionary < string , MaterialLookupDto > materialsByCode = new ( StringComparer . OrdinalIgnoreCase ) ;
if ( request . Items is { Count : > 0 } )
{
List < string > distinctCodes = request . Items
. Select ( i = > i . MaterialCode )
. Distinct ( StringComparer . OrdinalIgnoreCase )
. ToList ( ) ;
materialsByCode = await GetMaterialsAsync ( tc , distinctCodes ) ;
foreach ( string code in distinctCodes )
{
if ( ! materialsByCode . ContainsKey ( code ) )
throw new Exception ( $"Material code '{code}' does not exist." ) ;
}
}
var focItem = request . Items . FirstOrDefault ( x = > x . IsFocItem = = true ) ;
var dicountItem = request . Items . FirstOrDefault ( x = > x . DiscountAmount > 0 ) ;
List < SaveOrderPromotionRequest > promotions = new List < SaveOrderPromotionRequest > ( ) ;
request . FocValue = 0 ;
2026-07-19 10:04:03 +06:00
if ( dicountItem ! = null )
2026-07-16 18:30:18 +06:00
{
2026-07-19 10:04:03 +06:00
promotions . Add ( new SaveOrderPromotionRequest ( )
{
OrderId = isUpdate ? existingOrder . OrderId : 0 ,
MaterialId = materialsByCode [ dicountItem . MaterialCode ] . MaterialId ,
PromotionCode = request . DiscountCode ,
DiscountPercentage = dicountItem . DiscountPercentage ,
DiscountValue = dicountItem . DiscountAmount ,
ForQuantity = dicountItem . PromoQuantity ,
OrderFocQty = 0 ,
ValidatedFocQty = 0 ,
ApprovedFocQty = 0 ,
PromotionType = 1 ,
} ) ;
}
if ( focItem ! = null )
2026-07-16 18:30:18 +06:00
{
2026-07-19 10:04:03 +06:00
promotions . Add ( new SaveOrderPromotionRequest ( )
{
OrderId = isUpdate ? existingOrder . OrderId : 0 ,
MaterialId = materialsByCode [ focItem . MaterialCode ] . MaterialId ,
PromotionCode = request . FocCode ,
DiscountPercentage = 0 ,
DiscountValue = 0 ,
ForQuantity = focItem . PromoQuantity ,
OrderFocQty = ( request . OrderStatus = = OrderStatusEnum . Draft | | request . OrderStatus = = OrderStatusEnum . InOrderValidation ) ? focItem . OrderQuantity : 0 ,
ValidatedFocQty = ( request . OrderStatus = = OrderStatusEnum . CancelledByValidator | | request . OrderStatus = = OrderStatusEnum . InOrderApproval ) ? focItem . OrderQuantity : 0 ,
ApprovedFocQty = ( request . OrderStatus = = OrderStatusEnum . CancelledByApprover | | request . OrderStatus = = OrderStatusEnum . Approved ) ? focItem . OrderQuantity : 0 ,
PromotionType = 2 ,
} ) ;
2026-08-11 18:24:11 +06:00
}
decimal usedCreditBalance = await GetCurrentApprovedOrderAmountByCustomerAsync ( tc , request . CustomerCode , request . SalesOrgCode ) ;
if ( request . OrderStatus = = OrderStatusEnum . Approved & & customer . IsCreditCustomer & & request . PaymentTermCode ! = "0001" )
{
var customerLedger = await _httpService . GetCustomerLedgerAsync ( request . CustomerCode , customer . CompanyCode ) ;
2026-08-12 18:29:10 +06:00
if ( customerLedger = = null )
{
throw new Exception ( string . Format ( "Customer ledger is not found for this customer. Customer Code:{0}" , request . CustomerCode ) ) ;
}
2026-08-11 18:24:11 +06:00
var creditBalance = customer . CreditLimit - ( customerLedger . CurrentBalance + usedCreditBalance ) ;
if ( creditBalance < request . NetValue )
{
throw new Exception ( "Credit Limit is extend for this customer" ) ;
}
}
2026-07-16 18:30:18 +06:00
// 5. Insert or update
int orderId ;
if ( isUpdate )
{
orderId = existingOrder . OrderId ;
await UpdateOrderAsync ( tc , orderId , request , customer ! , paymentTerm ! , discount ! , materialsByCode , promotions , userId , ( int ) userRole ! . RoleId ) ;
response . IsNewOrder = ! isUpdate ;
response . UUID = request . UUID ;
response . OrderId = orderId ;
response . OrderDate = existingOrder . OrderDate ;
2026-07-23 11:11:46 +06:00
response . OrderNo = existingOrder . OrderNo ;
2026-07-16 18:30:18 +06:00
}
else
{
response = await InsertOrderAsync ( tc , request , customer ! , paymentTerm ! , discount ! , materialsByCode , promotions , userId , ( int ) userRole ! . RoleId ) ;
}
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
2026-07-15 18:51:09 +06:00
}
2026-07-16 18:30:18 +06:00
catch ( Exception )
2026-07-15 18:51:09 +06:00
{
2026-07-16 18:30:18 +06:00
throw ;
2026-07-15 18:51:09 +06:00
}
2026-07-16 18:30:18 +06:00
return response ;
}
2026-08-11 18:24:11 +06:00
private async Task < decimal > GetCurrentApprovedOrderAmountByCustomerAsync ( TransactionContext tc , string customerCode , string salesOrgCode )
{
decimal totalApprovedAmount = 0 ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@CustomerCode" , pType : SqlDbType . NVarChar , pValue : customerCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@SalesOrgCode" , pType : SqlDbType . NVarChar , pValue : salesOrgCode ) ,
] ;
using ( IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetCustomerApprovedAmount" , p ) )
{
if ( dr . Read ( ) )
{
totalApprovedAmount = dr . GetDecimal ( 0 ) ;
}
dr . Close ( ) ;
}
}
catch ( Exception )
{
throw ;
}
return totalApprovedAmount ;
}
2026-07-16 18:30:18 +06:00
private bool IsPermissiontoModify ( OrderStatusEnum orderStatus , UserRoleTypeEnum roleId )
{
if ( UserRoleTypeEnum . OrderCollector = = roleId & & ( OrderStatusEnum . Draft = = orderStatus | | OrderStatusEnum . InOrderValidation = = orderStatus ) )
{
return true ;
}
if ( UserRoleTypeEnum . OrderValidator = = roleId & & ( OrderStatusEnum . CancelledByValidator = = orderStatus | | OrderStatusEnum . InOrderApproval = = orderStatus ) )
2026-07-15 18:51:09 +06:00
{
2026-07-16 18:30:18 +06:00
return true ;
}
2026-07-26 18:04:49 +06:00
if ( UserRoleTypeEnum . OrderApprover = = roleId & & ( OrderStatusEnum . CancelledByApprover = = orderStatus | | OrderStatusEnum . Approved = = orderStatus ) )
{
return true ;
}
if ( UserRoleTypeEnum . OrderApproverWithoutValidated = = roleId & & ( OrderStatusEnum . CancelledByApprover = = orderStatus | | OrderStatusEnum . Approved = = orderStatus ) )
2026-07-16 18:30:18 +06:00
{
return true ;
}
return false ;
2026-07-15 18:51:09 +06:00
}
2026-07-16 18:30:18 +06:00
private async Task < UserRoleDto ? > GetUserRoleAsync ( TransactionContext tc , int userId )
{
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId )
] ;
using IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetUserRoleByUserId" , parameterValues : p ) ;
if ( dr . Read ( ) )
{
return new UserRoleDto { UserId = dr . GetInt32 ( 0 ) , RoleId = ( UserRoleTypeEnum ) dr . GetInt32 ( 1 ) } ;
}
return null ;
}
catch ( Exception )
{
throw ;
}
}
private async Task < OrderBasicResponse ? > GetExistingOrderIdAsync ( TransactionContext tc , Guid uuid )
{
OrderBasicResponse response = null ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UUID" , pType : SqlDbType . UniqueIdentifier , pValue : uuid )
] ;
using IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetOrderHeaderByUUID" , parameterValues : p ) ;
if ( dr . Read ( ) )
{
response = new OrderBasicResponse ( )
{
OrderId = dr . GetInt32 ( 0 ) ,
OrderNo = dr . GetString ( 1 ) ,
OrderDate = dr . GetDateTime ( 2 ) ,
UUID = uuid ,
OrderStatus = ( OrderStatusEnum ) dr . GetInt32 ( 3 )
} ;
}
dr . Close ( ) ;
}
catch ( Exception )
{
throw ;
}
return response ;
}
private async Task < CustomerLookupDto ? > GetCustomerAsync ( TransactionContext tc , string customerCode )
{
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@CustomerCode" , pType : SqlDbType . VarChar , pValue : customerCode )
] ;
using IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetCustomerByCode" , parameterValues : p ) ;
if ( dr . Read ( ) )
{
return new CustomerLookupDto
{
CustomerId = dr . GetInt32 ( 0 ) ,
CustomerCode = dr . GetString ( 1 ) ,
2026-08-11 18:24:11 +06:00
CustomerName = dr . GetString ( 2 ) ,
IsCreditCustomer = dr . GetInt32 ( 3 ) > 0 ,
CompanyCode = dr . GetString ( 4 ) ,
CreditLimit = dr . IsDBNull ( 5 ) ? 0 : dr . GetDecimal ( 5 )
2026-07-16 18:30:18 +06:00
} ;
}
return null ;
}
catch ( Exception )
{
throw ;
}
}
private async Task < PaymentTermLookupDto ? > GetPaymentTermAsync ( TransactionContext tc , string paymentTermCode , string salesOrgCode )
{
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@PaymentTermCode" , pType : SqlDbType . VarChar , pValue : paymentTermCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@SalesOrgCode" , pType : SqlDbType . VarChar , pValue : salesOrgCode )
] ;
using IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetPaymentTermByCode" , parameterValues : p ) ;
if ( dr . Read ( ) )
{
return new PaymentTermLookupDto { PaymentTermId = dr . GetInt32 ( 0 ) , PaymentTermCode = dr . GetString ( 1 ) } ;
}
return null ;
}
catch ( Exception )
{
throw ;
}
}
private async Task < DiscountLookupDto ? > GetDiscountAsync ( TransactionContext tc , string discountCode , string salesOrgCode )
{
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@DiscountCode" , pType : SqlDbType . VarChar , pValue : discountCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@SalesOrgCode" , pType : SqlDbType . VarChar , pValue : salesOrgCode )
] ;
using IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetDiscountByCode" , parameterValues : p ) ;
if ( dr . Read ( ) )
{
return new DiscountLookupDto { DiscountId = dr . GetInt32 ( 0 ) , DiscountCode = dr . GetString ( 1 ) } ;
}
return null ;
}
catch ( Exception )
{
throw ;
}
}
private async Task < bool > CheckFocCodeExistsAsync ( TransactionContext tc , string focCode , string salesOrgCode )
{
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@SalesOrgCode" , pType : SqlDbType . VarChar , pValue : salesOrgCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@FocCode" , pType : SqlDbType . VarChar , pValue : focCode )
] ;
using IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.CheckFocCodeExists" , parameterValues : p ) ;
return dr . Read ( ) ;
}
catch ( Exception )
{
throw ;
}
}
private async Task < Dictionary < string , MaterialLookupDto > > GetMaterialsAsync ( TransactionContext tc , IEnumerable < string > materialCodes )
{
try
{
Dictionary < string , MaterialLookupDto > result = new ( StringComparer . OrdinalIgnoreCase ) ;
DataTable codesTable = new ( ) ;
codesTable . Columns . Add ( "Code" , typeof ( string ) ) ;
foreach ( string code in materialCodes )
codesTable . Rows . Add ( code ) ;
SqlParameter codesParam = SqlHelperExtension . CreateInParam ( pName : "@Codes" , pType : SqlDbType . Structured , pValue : codesTable ) ;
codesParam . TypeName = "dbo.CodeListTableType" ; // CreateInParam has no TypeName slot, so it's set separately
SqlParameter [ ] p = [ codesParam ] ;
using IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetMaterialsByCodes" , parameterValues : p ) ;
while ( dr . Read ( ) )
{
MaterialLookupDto dto = new ( )
{
MaterialId = dr . GetInt32 ( 0 ) ,
MaterialCode = dr . GetString ( 1 ) ,
MaterialName = dr . GetString ( 2 )
} ;
result [ dto . MaterialCode ] = dto ;
}
dr . Close ( ) ;
return result ;
}
catch ( Exception )
{
throw ;
}
}
private async Task < List < FreeGoodsRuleDto > > GetFreeGoodsRulesAsync ( TransactionContext tc , string salesOrgCode , string focCode , IEnumerable < int > materialIds , DateTime ? asOfDate , int customerId )
{
try
{
List < FreeGoodsRuleDto > rules = new ( ) ;
DataTable idsTable = new ( ) ;
idsTable . Columns . Add ( "Id" , typeof ( int ) ) ;
foreach ( int id in materialIds )
idsTable . Rows . Add ( id ) ;
SqlParameter idsParam = SqlHelperExtension . CreateInParam ( pName : "@MaterialIds" , pType : SqlDbType . Structured , pValue : idsTable ) ;
idsParam . TypeName = "dbo.IntListTableType" ;
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@SalesOrgCode" , pType : SqlDbType . VarChar , pValue : salesOrgCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@CustomerId" , pType : SqlDbType . VarChar , pValue : customerId ) ,
SqlHelperExtension . CreateInParam ( pName : "@FocCode" , pType : SqlDbType . VarChar , pValue : focCode ) , idsParam ,
SqlHelperExtension . CreateInParam ( pName : "@AsOfDate" , pType : SqlDbType . DateTime , pValue : DateTime . Now )
] ;
using IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetFreeGoodsRules" , parameterValues : p ) ;
while ( dr . Read ( ) )
{
rules . Add ( new FreeGoodsRuleDto
{
FreeGoodsId = dr . GetInt32 ( 0 ) ,
MaterialId = dr . GetInt32 ( 1 ) ,
MinOrderQuantity = dr . GetDecimal ( 2 ) ,
ForQuantity = dr . GetDecimal ( 3 ) ,
FreeQuantity = dr . GetDecimal ( 4 ) ,
UnitOfMeasure = dr . IsDBNull ( 5 ) ? string . Empty : dr . GetString ( 5 ) ,
FocUnitOfMeasure = dr . IsDBNull ( 6 ) ? string . Empty : dr . GetString ( 6 )
} ) ;
}
dr . Close ( ) ;
return rules ;
}
catch ( Exception )
{
throw ;
}
}
// Once OrderQuantity >= MinOrderQuantity, the material earns FreeQuantity for every
// ForQuantity units ordered (e.g. Min 10 / For 10 / Free 1 -> ordering 25 = floor(25/10)*1 = 2 free).
// This is my read of "calculate based on order quantity" - swap the formula below if yours differs.
private static List < SaveOrderPromotionRequest > BuildFocPromotions ( SaveOrderRequest request ,
Dictionary < string , MaterialLookupDto > materialsByCode , List < FreeGoodsRuleDto > focRules )
{
try
{
List < SaveOrderPromotionRequest > promotions = new ( ) ;
Dictionary < int , FreeGoodsRuleDto > rulesByMaterialId = focRules
. GroupBy ( r = > r . MaterialId )
. ToDictionary ( g = > g . Key , g = > g . First ( ) ) ; // first active rule wins if more than one overlaps
foreach ( SaveOrderItemRequest item in request . Items )
{
if ( item . IsFocItem )
continue ; // a free item doesn't itself trigger more free goods
if ( ! materialsByCode . TryGetValue ( item . MaterialCode , out MaterialLookupDto ? material ) )
continue ; // already caught by validation - guarded here defensively
if ( ! rulesByMaterialId . TryGetValue ( material . MaterialId , out FreeGoodsRuleDto ? rule ) )
continue ; // no free-goods rule configured for this material under this FOC code
if ( rule . ForQuantity < = 0 | | item . OrderQuantity < rule . MinOrderQuantity )
continue ;
decimal eligibleSets = Math . Floor ( item . OrderQuantity / rule . ForQuantity ) ;
decimal focQuantity = eligibleSets * rule . FreeQuantity ;
if ( focQuantity < = 0 )
continue ;
promotions . Add ( new SaveOrderPromotionRequest
{
MaterialId = material . MaterialId ,
PromotionCode = request . FocCode ,
DiscountPercentage = 0 ,
DiscountValue = 0 ,
ForQuantity = rule . ForQuantity ,
OrderFocQty = focQuantity ,
ValidatedFocQty = 0 ,
ApprovedFocQty = 0 ,
PromotionType = 1 // TODO: swap for your real "free goods" PromotionType constant
} ) ;
}
return promotions ;
}
catch ( Exception )
{
throw ;
}
}
private static DataTable ToOrderItemTable ( IEnumerable < SaveOrderItemRequest > items , Dictionary < string , MaterialLookupDto > materialsByCode , int orderStatus )
{
try
{
DataTable table = new ( ) ;
table . Columns . Add ( "OrderId" , typeof ( int ) ) ;
table . Columns . Add ( "ItemId" , typeof ( int ) ) ;
table . Columns . Add ( "MaterialId" , typeof ( int ) ) ;
table . Columns . Add ( "MaterialCode" , typeof ( string ) ) ;
table . Columns . Add ( "MaterialName" , typeof ( string ) ) ;
table . Columns . Add ( "UnitPrice" , typeof ( decimal ) ) ;
table . Columns . Add ( "SalesUnit" , typeof ( string ) ) ;
table . Columns . Add ( "PromoQty" , typeof ( decimal ) ) ;
table . Columns . Add ( "OrderQuantity" , typeof ( decimal ) ) ;
table . Columns . Add ( "ValidatedQuantity" , typeof ( decimal ) ) ;
table . Columns . Add ( "ApprovedQuantity" , typeof ( decimal ) ) ;
table . Columns . Add ( "DiscountPercentage" , typeof ( decimal ) ) ;
table . Columns . Add ( "DiscountAmount" , typeof ( decimal ) ) ;
table . Columns . Add ( "IsFocItem" , typeof ( bool ) ) ;
table . Columns . Add ( "LineTotalValue" , typeof ( decimal ) ) ;
2026-07-27 18:12:06 +06:00
table . Columns . Add ( "VatValue" , typeof ( decimal ) ) ;
2026-07-16 18:30:18 +06:00
table . Columns . Add ( "OrderStatus" , typeof ( int ) ) ;
foreach ( SaveOrderItemRequest item in items )
{
MaterialLookupDto material = materialsByCode [ item . MaterialCode ] ;
table . Rows . Add (
item . ItemId ,
item . OrderId ,
material . MaterialId ,
item . MaterialCode ,
item . MaterialName ? ? material . MaterialName ,
item . UnitPrice ,
item . SalesUnit ,
item . PromoQuantity ,
item . OrderQuantity ,
item . ValidatedQuantity ,
item . ApprovedQuantity ,
item . DiscountPercentage ,
item . DiscountAmount ,
item . IsFocItem ,
item . LineTotalValue ,
2026-07-27 18:12:06 +06:00
item . VatValue ,
2026-07-16 18:30:18 +06:00
orderStatus ) ;
}
return table ;
}
catch ( Exception )
{
throw ;
}
}
private static DataTable ToOrderPromotionTable ( IEnumerable < SaveOrderPromotionRequest > promotions )
{
try
{
DataTable table = new ( ) ;
table . Columns . Add ( "ItemId" , typeof ( int ) ) ;
table . Columns . Add ( "OrderId" , typeof ( int ) ) ;
table . Columns . Add ( "MaterialId" , typeof ( int ) ) ;
table . Columns . Add ( "PromotionCode" , typeof ( string ) ) ;
table . Columns . Add ( "DiscountPercentage" , typeof ( decimal ) ) ;
table . Columns . Add ( "DiscountValue" , typeof ( decimal ) ) ;
table . Columns . Add ( "ForQuantity" , typeof ( decimal ) ) ;
table . Columns . Add ( "OrderFocQty" , typeof ( decimal ) ) ;
table . Columns . Add ( "ValidatedFocQty" , typeof ( decimal ) ) ;
table . Columns . Add ( "ApprovedFocQty" , typeof ( decimal ) ) ;
table . Columns . Add ( "PromotionType" , typeof ( int ) ) ;
foreach ( SaveOrderPromotionRequest promo in promotions )
{
table . Rows . Add (
promo . ItemId ,
promo . OrderId ,
promo . MaterialId ,
promo . PromotionCode ,
promo . DiscountPercentage ,
promo . DiscountValue ,
promo . ForQuantity ,
promo . OrderFocQty ,
promo . ValidatedFocQty ,
promo . ApprovedFocQty ,
promo . PromotionType ) ;
}
return table ;
}
catch ( Exception )
{
throw ;
}
}
private async Task < SaveOrderResponse > InsertOrderAsync ( TransactionContext tc , SaveOrderRequest request , CustomerLookupDto customer , PaymentTermLookupDto paymentTerm ,
DiscountLookupDto discount , Dictionary < string , MaterialLookupDto > materialsByCode ,
List < SaveOrderPromotionRequest > promotions , int userId , int role )
{
try
{
SqlParameter itemsParam = SqlHelperExtension . CreateInParam ( pName : "@Items" , pType : SqlDbType . Structured , pValue : ToOrderItemTable ( request . Items , materialsByCode , ( int ) request . OrderStatus ) ) ;
itemsParam . TypeName = "dbo.OrderItemTableType" ;
SqlParameter promotionsParam = SqlHelperExtension . CreateInParam ( pName : "@Promotions" , pType : SqlDbType . Structured , pValue : ToOrderPromotionTable ( promotions ) ) ;
promotionsParam . TypeName = "dbo.OrderPromotionTableType" ;
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@UUID" , pType : SqlDbType . UniqueIdentifier , pValue : request . UUID ) ,
SqlHelperExtension . CreateInParam ( pName : "@OrderNo" , pType : SqlDbType . VarChar , pValue : request . OrderNo ) ,
SqlHelperExtension . CreateInParam ( pName : "@OrderDate" , pType : SqlDbType . DateTime , pValue : request . OrderDate ? ? DateTime . Now ) ,
SqlHelperExtension . CreateInParam ( pName : "@ExpectedDeliveryDate" , pType : SqlDbType . DateTime , pValue : request . ExpectedDeliveryDate ) ,
SqlHelperExtension . CreateInParam ( pName : "@SalesOrgCode" , pType : SqlDbType . VarChar , pValue : request . SalesOrgCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@CustomerId" , pType : SqlDbType . Int , pValue : customer . CustomerId ) ,
SqlHelperExtension . CreateInParam ( pName : "@CustomerCode" , pType : SqlDbType . VarChar , pValue : request . CustomerCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@CustomerName" , pType : SqlDbType . VarChar , pValue : request . CustomerName ) ,
SqlHelperExtension . CreateInParam ( pName : "@EmployeeId" , pType : SqlDbType . Int , pValue : request . EmployeeId ) ,
SqlHelperExtension . CreateInParam ( pName : "@EmployeeCode" , pType : SqlDbType . VarChar , pValue : request . EmployeeCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@EmployeeName" , pType : SqlDbType . VarChar , pValue : request . EmployeeCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@PaymentTermCode" , pType : SqlDbType . VarChar , pValue : request . PaymentTermCode ) ,
2026-07-27 18:12:06 +06:00
SqlHelperExtension . CreateInParam ( pName : "@DiscountCode" , pType : SqlDbType . VarChar , pValue : request . DiscountCode ) ,
2026-07-18 18:55:29 +06:00
SqlHelperExtension . CreateInParam ( pName : "@FOCCode" , pType : SqlDbType . VarChar , pValue : request . FocCode ) ,
2026-07-16 18:30:18 +06:00
SqlHelperExtension . CreateInParam ( pName : "@ReferenceTxtNo" , pType : SqlDbType . VarChar , pValue : request . ReferenceTxtNo ) ,
SqlHelperExtension . CreateInParam ( pName : "@GrossValue" , pType : SqlDbType . Decimal , pValue : request . GrossValue ) ,
SqlHelperExtension . CreateInParam ( pName : "@DiscountValue" , pType : SqlDbType . Decimal , pValue : request . DiscountValue ) ,
2026-07-27 18:12:06 +06:00
SqlHelperExtension . CreateInParam ( pName : "@TotalVatValue" , pType : SqlDbType . VarChar , pValue : request . TotalVatValue ) ,
2026-07-16 18:30:18 +06:00
SqlHelperExtension . CreateInParam ( pName : "@FOCValue" , pType : SqlDbType . Decimal , pValue : request . FocCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@NetValue" , pType : SqlDbType . Decimal , pValue : request . NetValue ) ,
SqlHelperExtension . CreateInParam ( pName : "@OrderStatus" , pType : SqlDbType . Int , pValue : ( int ) request . OrderStatus ) ,
SqlHelperExtension . CreateInParam ( pName : "@SapRefferenceOrderNo" , pType : SqlDbType . NVarChar , pValue : null ) ,
2026-07-19 10:04:03 +06:00
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
2026-07-16 18:30:18 +06:00
itemsParam ,
promotionsParam
] ;
using IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.InsertOrder" , parameterValues : p ) ;
int newOrderId = 0 ;
string orderNo = string . Empty ;
if ( dr . Read ( ) )
{
newOrderId = dr . GetInt32 ( 0 ) ;
orderNo = dr . GetString ( 1 ) ;
}
dr . Close ( ) ;
return new SaveOrderResponse ( ) { IsNewOrder = true , OrderDate = DateTime . Now , OrderId = newOrderId , OrderNo = orderNo , UUID = request . UUID } ;
}
catch ( Exception )
{
throw ;
}
}
private async Task UpdateOrderAsync ( TransactionContext tc , int orderId , SaveOrderRequest request , CustomerLookupDto customer , PaymentTermLookupDto paymentTerm ,
DiscountLookupDto discount , Dictionary < string , MaterialLookupDto > materialsByCode ,
List < SaveOrderPromotionRequest > promotions , int userId , int role )
{
try
{
SqlParameter itemsParam = SqlHelperExtension . CreateInParam ( pName : "@Items" , pType : SqlDbType . Structured , pValue : ToOrderItemTable ( request . Items , materialsByCode , ( int ) request . OrderStatus ) ) ;
itemsParam . TypeName = "dbo.OrderItemTableType" ;
SqlParameter promotionsParam = SqlHelperExtension . CreateInParam ( pName : "@Promotions" , pType : SqlDbType . Structured , pValue : ToOrderPromotionTable ( promotions ) ) ;
promotionsParam . TypeName = "dbo.OrderPromotionTableType" ;
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@OrderId" , pType : SqlDbType . Int , pValue : orderId ) ,
SqlHelperExtension . CreateInParam ( pName : "@ExpectedDeliveryDate" , pType : SqlDbType . DateTime , pValue : request . ExpectedDeliveryDate ) ,
SqlHelperExtension . CreateInParam ( pName : "@PaymentTermCode" , pType : SqlDbType . VarChar , pValue : request . PaymentTermCode ) ,
2026-07-18 18:55:29 +06:00
SqlHelperExtension . CreateInParam ( pName : "@DiscountCode" , pType : SqlDbType . VarChar , pValue : request . DiscountCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@FOCCode" , pType : SqlDbType . VarChar , pValue : request . FocCode ) ,
2026-07-16 18:30:18 +06:00
SqlHelperExtension . CreateInParam ( pName : "@ReferenceTxtNo" , pType : SqlDbType . VarChar , pValue : request . ReferenceTxtNo ) ,
SqlHelperExtension . CreateInParam ( pName : "@GrossValue" , pType : SqlDbType . Decimal , pValue : request . GrossValue ) ,
SqlHelperExtension . CreateInParam ( pName : "@DiscountValue" , pType : SqlDbType . Decimal , pValue : request . DiscountValue ) ,
2026-07-27 18:12:06 +06:00
SqlHelperExtension . CreateInParam ( pName : "@TotalVatValue" , pType : SqlDbType . VarChar , pValue : request . TotalVatValue ) ,
2026-07-16 18:30:18 +06:00
SqlHelperExtension . CreateInParam ( pName : "@FOCValue" , pType : SqlDbType . Decimal , pValue : request . FocCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@NetValue" , pType : SqlDbType . Decimal , pValue : request . NetValue ) ,
SqlHelperExtension . CreateInParam ( pName : "@OrderStatus" , pType : SqlDbType . Int , pValue : ( int ) request . OrderStatus ) ,
2026-07-19 10:04:03 +06:00
SqlHelperExtension . CreateInParam ( pName : "@UserId" , pType : SqlDbType . Int , pValue : userId ) ,
2026-07-16 18:30:18 +06:00
itemsParam ,
promotionsParam
] ;
using IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.UpdateOrder" , parameterValues : p ) ;
dr . Close ( ) ;
}
catch ( Exception )
{
throw ;
}
}
2026-07-18 18:55:29 +06:00
public async Task < PagedResult < GetSalesOrderResponse > > GetSalesOrdersSummary ( GetOrderSummaryRequest request , int userId )
{
PagedResult < GetSalesOrderResponse ? > response = null ;
List < GetSalesOrderResponse > orders = new ( ) ;
List < GetSalesOrderItemResponse > orderItems = new ( ) ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@SalesOrgCode" , pType : SqlDbType . VarChar , pValue : request . SalesOrgCode ) ,
2026-07-23 11:11:46 +06:00
SqlHelperExtension . CreateInParam ( pName : "@EmployeeCode" , pType : SqlDbType . VarChar , pValue : request . EmployeeCode ) ,
2026-07-18 18:55:29 +06:00
SqlHelperExtension . CreateInParam ( pName : "@OrderNo" , pType : SqlDbType . VarChar , pValue : request . OrderNo ) ,
SqlHelperExtension . CreateInParam ( pName : "@UUID" , pType : SqlDbType . VarChar , pValue : request . UUID ) ,
SqlHelperExtension . CreateInParam ( pName : "@CustomerCode" , pType : SqlDbType . VarChar , pValue : request . CustomerCode ) ,
SqlHelperExtension . CreateInParam ( pName : "@OrderStatus" , pType : SqlDbType . Int , pValue : ( int? ) request . OrderStatus ) ,
SqlHelperExtension . CreateInParam ( pName : "@StartDate" , pType : SqlDbType . DateTime , pValue : request . StartDate ) ,
SqlHelperExtension . CreateInParam ( pName : "@EndDate" , pType : SqlDbType . DateTime , pValue : request . EndDate ) ,
SqlHelperExtension . CreateInParam ( pName : "@PageNumber" , pType : SqlDbType . Int , pValue : request . PageNumber ) ,
SqlHelperExtension . CreateInParam ( pName : "@PageSize" , pType : SqlDbType . Int , pValue : request . PageSize )
] ;
using ( IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetOrderSummaryPaginated" , parameterValues : p ) )
{
// --- Result set 1: order header ---
while ( dr . Read ( ) )
{
orders . Add ( new GetSalesOrderResponse
{
OrderId = dr . GetInt32 ( 16 ) ,
Uuid = dr . GetGuid ( 0 ) ,
OrderNo = dr . GetString ( 1 ) ,
OrderDate = dr . GetDateTime ( 2 ) ,
ExpectedDeliveryDate = dr . IsDBNull ( 3 ) ? null : dr . GetDateTime ( 3 ) ,
SalesOrgCode = dr . GetString ( 4 ) ,
CustomerCode = dr . GetString ( 5 ) ,
CustomerName = dr . GetString ( 6 ) ,
ReferenceTxtNo = dr . IsDBNull ( 7 ) ? null : dr . GetString ( 7 ) ,
EmployeeCode = dr . GetString ( 8 ) ,
PaymentTermCode = dr . GetString ( 9 ) ,
DiscountCode = dr . IsDBNull ( 10 ) ? string . Empty : dr . GetString ( 10 ) ,
FocCode = dr . IsDBNull ( 11 ) ? string . Empty : dr . GetString ( 11 ) ,
DiscountValue = dr . GetDecimal ( 12 ) ,
GrossValue = dr . GetDecimal ( 13 ) ,
NetValue = dr . GetDecimal ( 14 ) ,
2026-07-27 18:12:06 +06:00
OrderStatus = dr . GetInt32 ( 15 ) ,
2026-08-11 18:24:11 +06:00
TotalVatValue = dr . IsDBNull ( 17 ) ? null : dr . GetDecimal ( 17 ) ,
BillingNumber = dr . IsDBNull ( 18 ) ? null : dr . GetString ( 18 ) ,
BillingDate = dr . IsDBNull ( 19 ) ? null : dr . GetDateTime ( 19 )
2026-07-18 18:55:29 +06:00
} ) ;
}
// --- Result set 2: order items ---
if ( orders . Count > 0 & & dr . NextResult ( ) )
{
while ( dr . Read ( ) )
{
orderItems . Add ( new GetSalesOrderItemResponse
{
OrderId = dr . GetInt32 ( 0 ) ,
UUID = dr . GetGuid ( 1 ) ,
MaterialCode = dr . GetString ( 2 ) ,
MaterialName = dr . GetString ( 3 ) ,
UnitPrice = dr . GetDecimal ( 4 ) ,
SalesUnit = dr . GetString ( 5 ) ,
2026-07-19 16:05:07 +06:00
PromoQuantity = dr . IsDBNull ( 6 ) ? null : dr . GetDecimal ( 6 ) ,
OrderQuantity = dr . IsDBNull ( 7 ) ? null : dr . GetDecimal ( 7 ) ,
ValidatedQuantity = dr . IsDBNull ( 8 ) ? null : dr . GetDecimal ( 8 ) ,
ApprovedQuantity = dr . IsDBNull ( 9 ) ? null : dr . GetDecimal ( 9 ) ,
DiscountPercentage = dr . IsDBNull ( 10 ) ? null : dr . GetDecimal ( 10 ) ,
DiscountAmount = dr . IsDBNull ( 11 ) ? null : dr . GetDecimal ( 11 ) ,
2026-07-18 18:55:29 +06:00
IsFocItem = dr . GetInt32 ( 12 ) > 0 ,
2026-07-27 18:12:06 +06:00
LineTotalValue = dr . GetDecimal ( 13 ) ,
VatValue = dr . IsDBNull ( 14 ) ? null : dr . GetDecimal ( 14 )
2026-07-18 18:55:29 +06:00
} ) ;
}
}
dr . Close ( ) ;
}
tc . End ( ) ;
foreach ( var order in orders )
{
order . Items = orderItems . Where ( i = > i . OrderId = = order . OrderId ) . ToList ( ) ;
}
response = new PagedResult < GetSalesOrderResponse >
{
Items = orders ,
TotalCount = orders . Count ,
PageNumber = request . PageNumber ,
PageSize = request . PageSize
} ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception ex )
{
throw ;
}
return response ;
}
2026-07-20 18:30:13 +06:00
public async Task < IList < int > > GetAvailableOrderIdsForSAPAsync ( SAPOrderStatusEnum orderStaus , CancellationToken cancellationToken = default )
{
List < int > response = new List < int > ( ) ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@OrderStatus" , pType : SqlDbType . Int , pValue : ( int? ) orderStaus ) ,
] ;
using ( IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetAvailableOrderIdsByStatus" , parameterValues : p ) )
{
while ( dr . Read ( ) )
{
response . Add ( dr . GetInt32 ( 0 ) ) ;
}
dr . Close ( ) ;
}
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception ex )
{
throw ;
}
return response ;
}
public async Task < GetOrderForSAPResponse ? > GetOrderDetailsForSapByIdAsync ( int orderId , CancellationToken cancellationToken = default )
{
GetOrderForSAPResponse response = null ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@OrderId" , pType : SqlDbType . Int , pValue : orderId ) ,
] ;
using ( IDataReader dr = await tc . ExecuteReaderSpAsync ( "dbo.GetOrderDetailsById" , parameterValues : p ) )
{
while ( dr . Read ( ) )
{
response = new GetOrderForSAPResponse ( )
{
SalesOrderType = dr . GetString ( 0 ) ,
SalesOrganization = dr . GetString ( 1 ) ,
DistributionChannel = dr . GetString ( 2 ) ,
OrganizationDivision = dr . GetString ( 3 ) ,
SoldToParty = dr . GetString ( 4 ) ,
PurchaseOrderByCustomer = dr . GetString ( 5 ) ,
CustomerPurchaseOrderDate = ConvertOrderDateIntoMilisec ( dr . GetDateTime ( 6 ) ) ,
PurchaseOrderByShipToParty = dr . IsDBNull ( 7 ) ? null : dr . GetString ( 7 ) ,
CustomerPaymentTerms = dr . IsDBNull ( 8 ) ? null : dr . GetString ( 8 ) ,
CustomerGroup = dr . GetString ( 9 ) ,
CustomerPriceGroup = dr . GetString ( 10 )
} ;
}
if ( response is not null & & dr . NextResult ( ) )
{
while ( dr . Read ( ) )
{
response . to_Item . Add ( new GetOrderItemForSAPResponse
{
Material = dr . GetString ( 0 ) ,
RequestedQuantity = Convert . ToString ( dr . IsDBNull ( 1 ) ? 0 : dr . GetDecimal ( 1 ) )
} ) ;
}
}
dr . Close ( ) ;
}
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception ex )
{
throw ;
}
return response ;
}
private string ConvertOrderDateIntoMilisec ( DateTime orderDate )
{
long milliseconds = new DateTimeOffset ( orderDate ) . ToUnixTimeMilliseconds ( ) ;
string sapDate = $"/Date({milliseconds})/" ;
return sapDate ;
}
public async Task < bool > UpdateSendingSapDetailsAsync ( UpdateSapDetailsRequest request , CancellationToken cancellationToken = default )
{
bool response = false ;
try
{
using TransactionContext tc = await TransactionContext . BeginAsync ( _settings . DefaultConnection . ConnectionNode , true ) ;
try
{
SqlParameter [ ] p =
[
SqlHelperExtension . CreateInParam ( pName : "@OrderId" , pType : SqlDbType . Int , pValue : request . OrderId ) ,
2026-07-21 13:10:16 +06:00
SqlHelperExtension . CreateInParam ( pName : "@OrderNo" , pType : SqlDbType . NVarChar , pValue : request . SapOrderNo ) ,
2026-07-20 18:30:13 +06:00
SqlHelperExtension . CreateInParam ( pName : "@Status" , pType : SqlDbType . Int , pValue : request . Status ) ,
SqlHelperExtension . CreateInParam ( pName : "@SentAt" , pType : SqlDbType . DateTime , pValue : DateTime . Now ) ,
SqlHelperExtension . CreateInParam ( pName : "@RetryCount" , pType : SqlDbType . Int , pValue : request . RetryCount ) ,
SqlHelperExtension . CreateInParam ( pName : "@LastError" , pType : SqlDbType . Int , pValue : request . LastError ) ,
SqlHelperExtension . CreateInParam ( pName : "@ReturnMessage" , pType : SqlDbType . Int , pValue : request . ReturnMessage ) ,
] ;
2026-07-21 13:10:16 +06:00
tc . ExecuteNonQuerySp ( "dbo.UpdateSendingSapDetails" , parameterValues : p ) ;
2026-07-20 18:30:13 +06:00
tc . End ( ) ;
}
catch ( Exception ie )
{
tc ? . HandleError ( ) ;
throw DBCustomError . GenerateCustomError ( ie ) ;
}
}
catch ( Exception ex )
{
throw ;
}
return response ;
}
2026-07-15 18:51:09 +06:00
}