using Sarand.BusinessMgr.Net.Standard.Base.App; using Sarand.BusinessMgr.Net.Standard.Base.Bus; using Sarand.BusinessMgr.Net.Standard.Dbas.Bus; using Sarand.BusinessMgr.Net.Standard.Dbas.Internal; using Sarand.BusinessMgr.Net.Standard.Dbas.UpdateLog; using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Bus; using Sarand.Net.Standard.Base.Core; using Sarand.Net.Standard.Base.Dbas; using Sarand.Net.Standard.Base.ReferenceData; using Sarand.Net.Standard.Base.Utils; using Sarand.Net.Standard.Dbas.Base; using Sarand.Net.Standard.Dbas.Data; using System; using System.Collections.Generic; using System.Data.Common; using System.Linq; using System.Text.RegularExpressions; using System.Transactions; namespace Sarand.BusinessMgr.Net.Standard.Dbas.Mgr { //======================================================================= // Transaction manager - Transactions - Utils. //======================================================================= partial class SbmTransactionMgr_Dbas { //------------------------------------------------------------------- // Read only. public override bool TransactionIsReadOnly(SbmTransaction transaction) { if (!SysId.IsValid(transaction.Id)) return false; bool bReadOnly = false; // Transaction can't be updated after it has been exporetd to an accounts system. if (!bReadOnly) { if (AccountsDfn.IsTransactionTypeManagedByAccounts(transaction.TransactionType)) bReadOnly = true; } return bReadOnly; } public override bool TransactionDetailsAreReadOnly(SbmTransaction transaction) { if (!SysId.IsValid(transaction.Id)) return false; if (TransactionIsReadOnly(transaction)) return true; // If transaction is read only then details must be. bool detailsAreReadOnly = false; // User must be allowed to update transactions: if (!detailsAreReadOnly) { // ToDo UserCanUpdateItemType /*if (!pSys->UserCanUpdateItemType(eSapItemTypeTransaction)) bDetailsAreReadOnly = true;*/ } // Closed transactions. if (!detailsAreReadOnly) { if (transaction.TransactionStatusCat == SbmTransaction.StatusCat.Closed) { // Once the 'grace' period has passed, only the status can be modified. int graceDaysUpdateClosedTrans = Math.Max(0, Internals.GetOwnerOption_UpdateLimit(Sbm.OrgOption_PeriodDays.UpdateClosedTransaction, 0)); DateTime closed = transaction.Closed; detailsAreReadOnly = (DateUtil.IsValid(closed) && closed <= DateTime.Today.AddDays(-graceDaysUpdateClosedTrans)); } } return detailsAreReadOnly; } //------------------------------------------------------------------- // Transaction properties. public override Sbm.TransactionType GetTransactionType(SysId transactionId) { if (SysId.IsValid(transactionId)) { // Construct the query. String colType = "TransType"; DbQuery qry = new DbQuery(Database.DbmsType); qry.Tables.Add(SbmDbDfn.GetTableName(SbmDbDfn.TableIdx.Transaction)); qry.Columns.Add(SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Transaction_Type), colType); qry.Filters.Add($"{SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Transaction_Id)}={SysId.ToLong(transactionId)}"); using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(Database, qry.BuildQuery())) { if (dbResultSet != null && dbResultSet.NextRecord()) { NamedValue.Map values = dbResultSet.GetRecordValues(); return (Sbm.TransactionType)values.GetLong(colType); } } } return Sbm.TransactionType.Unknown; } //------------------------------------------------------------------- public override bool RefreshTransactionTotals(SbmTransaction transaction, IEnumerable requirements) { // Recalculate the amounts stored against the transaction in line with the list of requirements. ClearErrorState(); if (transaction == null) return SetErrorState(ErrorMessage.ItemNotSpecified); if (requirements == null) requirements = new List(); // Total weight. SysId uomIdWeight = transaction.UomIdWeight; if (!SysId.IsValid(uomIdWeight)) uomIdWeight = Internals.GetDefaultUnitOfMeasureByCategory(SaUomCategory.Weight)?.Id; transaction.Weight = requirements.GetTotalWeight(uomIdWeight); // Set the allocation status: transaction.ClearAllocationStatus(); if (requirements.IsFullAllocation()) transaction.FullAllocation = true; else if (requirements.IsPartialAllocation()) transaction.PartialAllocation = true; // Calculate the totals from the list of requirements: decimal totalAmountNet = 0.0m, totalAmountTax = 0.0m, totalAmountTot = 0.0m, totalTimeEst = 0.0m, totalTimeAct = 0.0m; requirements.CalculateTotals(ref totalAmountNet, ref totalAmountTax, ref totalAmountTot, ref totalTimeEst, ref totalTimeAct); // Include delivery amounts: totalAmountNet += transaction.DeliveryAmountNet; totalAmountTax += transaction.DeliveryAmountTax; totalAmountTot += transaction.DeliveryAmountTot; // Store amounts: transaction.AmountNet = totalAmountNet; transaction.AmountTax = totalAmountTax; transaction.AmountTot = totalAmountTot; transaction.TimeEst = totalTimeEst; transaction.TimeAct = totalTimeAct; return OK; } //------------------------------------------------------------------- // Labour Cost. public override decimal GetTransCostLabourRateHourDefault() { String costLabourRateHour = Internals.GetOwnerOption_Value(Sbm.OrgOption_Value.CostLabourRateDefault); return costLabourRateHour.ToDecimal(); } // ToDo GetTransCostLabourRateHourDefault & GetTransCostLabourRateHour for conversion datatype double to decimal! public override decimal GetTransCostLabourRateHour(SysId transactionId) { string colCostLabourRateHour = "CostLabourRateHour"; decimal labourRate = 0.0m; if (SysId.IsValid(transactionId)) { labourRate = GetTransCostLabourRateHourDefault(); if (ColumnExists(SbmDbDfn.ColumnIdx.Transaction_CostLabourRateHour)) { // Construct the query. DbQuery qry = new DbQuery(Database.DbmsType); qry.Tables.Add(SbmDbDfn.GetTableName(SbmDbDfn.TableIdx.Transaction)); qry.Columns.Add(SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Transaction_CostLabourRateHour), colCostLabourRateHour); qry.Filters.Add(SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Transaction_Id) + "=" + transactionId.ToString()); qry.Filters.Add(SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Transaction_CostLabourRateHour) + " IS NOT null"); using (DbResultSet dbResultSet = DbResultSet_DataReader.ExecuteQuery(Database, qry.BuildQuery())) { if (dbResultSet != null && dbResultSet.NextRecord()) { NamedValue.Map values = dbResultSet.GetRecordValues(); return (decimal)values.GetValue(colCostLabourRateHour).ToNumeric(); } } } } return labourRate; } public override bool DeliveryFinancialsAreAvailable() { // Are the fields defined on the database? if (ColumnExists(SbmDbDfn.ColumnIdx.Transaction_DeliveryAmountNet)) return false; if (ColumnExists(SbmDbDfn.ColumnIdx.Transaction_DeliveryAmountTax)) return false; if (!ColumnExists(SbmDbDfn.ColumnIdx.Transaction_DeliveryAmountTot)) return false; if (!ColumnExists(SbmDbDfn.ColumnIdx.Transaction_TaxCodeIdDelivery)) return false; if (!ColumnExists(SbmDbDfn.ColumnIdx.Transaction_DeliveryDepartment)) return false; if (!ColumnExists(SbmDbDfn.ColumnIdx.Transaction_DeliveryNominalCode)) return false; return true; } //------------------------------------------------------------------- /// /// Change association against transaction and dependent data. /// public override bool ChangeTransactionsAssociation(SbmTransaction transaction, SysId assocId) { ClearErrorState(); List filters = new List(); List values = new List(); String errorStatePrefix = "Failed to change transaction's association - "; // Database connection. if (!HasErrorState() && Database == null) SetErrorState(errorStatePrefix + ErrorMessage.DatabaseNotAvailable); // Validate the transaction. if (!HasErrorState() && (transaction == null || !SysId.IsValid(transaction.Id))) SetErrorState(errorStatePrefix + "invalid transaction specified"); ///### Apr2012 Don't bother checking that the transaction's assocition is different ### /* Check that the association is not the same as the current association. if (!HasErrorState() && transaction.AssocId == assocId) SetErrorState(errorStatePrefix+"a different association must be specified");*/ // Check that the specified association exists. if (!HasErrorState() && AccountMgr != null && !AccountMgr.AssociationExistsById(assocId)) SetErrorState(errorStatePrefix + "specified association doesn't exist"); // Replace the association against subordinate data items. if (!HasErrorState() && TransactionHasConstituents(transaction.Id, SbmConstituent.StatusCat.NotDeleted)) { SacsDatabase.AddValuePair(values, SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Constituent_AssocId), assocId.ToString(), false); filters.Add(SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Constituent_TransId) + "=" + transaction.Id.ToString()); Database.ExecuteUpdate(SbmDbDfn.GetTableName(SbmDbDfn.TableIdx.Constituent), values, filters.Concat(" AND ", "(", ")")); if (Database.HasErrorState()) { SetErrorState(errorStatePrefix + "transaction updates failed"); ChangeTransactionsAssociation(transaction, transaction.AssociationId); // To reset changes. } } if (!HasErrorState() && TransactionHasRequirements(transaction.Id, SbmRequirement.StatusCat.NotDeleted)) { SacsDatabase.AddValuePair(values, SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Requirement_AssocId), assocId.ToString(), false); filters.Add(SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Requirement_TransId) + "=" + transaction.Id.ToString()); Database.ExecuteUpdate(SbmDbDfn.GetTableName(SbmDbDfn.TableIdx.Requirement), values, filters.Concat(" AND ", "(", ")")); if (Database.HasErrorState()) { SetErrorState(errorStatePrefix + "requirement updates failed"); ChangeTransactionsAssociation(transaction, transaction.AssociationId); // To reset changes. } }// Replace the association against the transaction itself. if (!HasErrorState() && transaction.AssociationId != assocId) { filters.Clear(); values.Clear(); SacsDatabase.AddValuePair(values, SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Transaction_AssocId), assocId.ToString(), false); filters.Add(SbmDbDfn.GetColumnName(SbmDbDfn.ColumnIdx.Transaction_Id) + "=" + transaction.Id.ToString()); Database.ExecuteUpdate(SbmDbDfn.GetTableName(SbmDbDfn.TableIdx.Transaction), values, filters.Concat(" AND ", "(", ")")); if (Database.HasErrorState()) { SetErrorState(errorStatePrefix + "transaction update failed"); ChangeTransactionsAssociation(transaction, transaction.AssociationId); // To reset changes. } } return OK; } //------------------------------------------------------------------- // Transaction Subordinate data. /// Commit Subordinate data - Payments. public override bool CommitTransactionSubordinateData(SbmTransaction transaction, DbUpdateInfo dbUpdateInfo) { ClearErrorState(); if (transaction == null || !SysId.IsValid(transaction.Id)) return false; if (!HasErrorState()) CommitTransactionPayments(transaction, dbUpdateInfo); return OK; } public override bool TransactionHasPayments(SysId transactionId) { if (!SysId.IsValid(transactionId)) return false; SbmItemLink.Params prmItemLink = new SbmItemLink.Params(); prmItemLink.ItemLinkType = Sbm.ItemLinkType.Transaction_Payment; prmItemLink.ItemTypeFrom = Sbm.ItemType.Transaction; prmItemLink.ItemIdFrom = transactionId; return DataItemMgr.GetItemLinkCount(prmItemLink) > 0; } public override List GetTransactionPayments(SysId transactionId) { List transactionPayments = new List(); if (!SysId.IsValid(transactionId)) return transactionPayments; SbmItemLink.Params prm = new SbmItemLink.Params(); prm.ItemLinkType = Sbm.ItemLinkType.Transaction_Payment; prm.ItemTypeFrom = Sbm.ItemType.Transaction; prm.ItemIdFrom = transactionId; foreach (SbmItemLink itemLink in DataItemMgr.GetItemLinkList(prm)) { SbmTransactionPayment transactionPayment = new SbmTransactionPayment(itemLink.DataContent); transactionPayment.Notes = itemLink.Notes; transactionPayment.Changed = false; if (transactionPayments == null) transactionPayments = new List(); transactionPayments.Add(transactionPayment); } transactionPayments.Sort(); return transactionPayments; } public override bool CommitTransactionPayments(SbmTransaction transaction, DbUpdateInfo dbUpdateInfo) { ClearErrorState(); // Do not attempt any updates unless the list has been populated. if (transaction == null || !SysId.IsValid(transaction.Id) || transaction.Payments == null) return false; // Build an item link list corresponding to the list of payment: List itemLinks = new List(); foreach (SbmTransactionPayment transactionPayment in transaction.Payments) { if (transactionPayment == null) continue; SbmItemLink itemLink = DataItemMgr.CreateItemLink(Sbm.ItemLinkType.Transaction_Payment, Sbm.ItemType.Transaction, transaction.Id, Sbm.ItemType.Unknown, new SysId(0)); if (itemLink != null) { itemLink.Seq = (short)transactionPayment.CodeSeq; itemLink.DataContent = transactionPayment.ToString(); itemLink.Notes = transactionPayment.Notes; itemLinks.Add(itemLink); itemLink = null; // Now owned by the list. } } // Store these details: if (!DataItemMgr.StoreFromItemLinks(Sbm.ItemLinkType.Transaction_Payment, transaction.GetItemId(), itemLinks, dbUpdateInfo)) SetErrorState("Failed to save transaction payment item links - " + DataItemMgr.ErrorStateMessage); return true; } //------------------------------------------------------------------- } //======================================================================= }