/// <summary> /// Расчет стоимости накладной в учетных ценах /// </summary> /// <param name="waybill">Приходная накладная</param> /// <param name="user">Пользователь</param> /// <param name="excludeDivergences">Исключить ли суммы по позициям с расхождениями</param> /// <returns>Сумма в учетных ценах. Если не удалось рассчитать, то null</returns> public decimal?CalcAccountingPriceSum(ReceiptWaybill waybill, User user, bool excludeDivergences) { decimal?result = 0; // если накладная не проведена - считаем по текущим УЦ if (!waybill.IsAccepted) { result = CalcCurrentAccountingPriceSum(waybill.Rows, waybill.Id, waybill.ReceiptStorage, user); } // если накладная принята с расхождениями (т.е. принята, но не согласована) else if (waybill.ReceiptDate != null && !waybill.IsApproved) { // считаем сумму в УЦ для позиций без расхождений result = waybill.Rows.Where(x => !x.AreDivergencesAfterReceipt).Sum(x => Math.Round(x.CurrentCount * x.RecipientArticleAccountingPrice.AccountingPrice, 2)); // если включаем позиции с расхождениями if (!excludeDivergences) { // для позиций, добавленных при приемке, берем 0 result += waybill.Rows.Where(x => x.AreDivergencesAfterReceipt) .Sum(x => Math.Round(x.CurrentCount * (x.RecipientArticleAccountingPrice != null ? x.RecipientArticleAccountingPrice.AccountingPrice : 0), 2)); } } // если накладная проведена, но не принята; принята без расхождений; согласована после расхождений else { result = waybill.Rows.Sum(x => Math.Round(x.CurrentCount * x.RecipientArticleAccountingPrice.AccountingPrice, 2)); } return(result); }
/// <summary> /// Пересчет финансовых показателей после отмены окончательного согласования приходной накладной /// </summary> /// <param name="waybill">Приходная накладная</param> public void ReceiptWaybillApprovementCancelled(ReceiptWaybill waybill) { //для расчета учетных сумм decimal currentAccountingSum = 0M, currentPurchaseCostSum = 0M; // если есть позиции с расхождениями после приемки if (waybill.AreDivergencesAfterReceipt) { // позиции с расхождениями при приемке var rows = waybill.Rows.Where(x => x.AreDivergencesAfterReceipt == true || x.PendingCount == 0); // расчет суммы в учетных ценах currentAccountingSum = CalculateReceiptWaybillAccountingPriceSumByRows(rows); // расчет суммы в закупочных ценах currentPurchaseCostSum = CalculateReceiptWaybillPurchaseCostSumByRows(rows); } else { // берем все позиции накладной var rows = waybill.Rows; // расчет суммы в учетных ценах currentAccountingSum = CalculateReceiptWaybillAccountingPriceSumByRows(rows); // расчет суммы в закупочных ценах currentPurchaseCostSum = CalculateReceiptWaybillPurchaseCostSumByRows(rows); } articleMovementFactualFinancialIndicatorService.Update(waybill.ApprovementDate.Value, null, null, waybill.AccountOrganization.Id, waybill.ReceiptStorage.Id, ArticleMovementOperationType.Receipt, waybill.Id, -currentPurchaseCostSum, -currentAccountingSum, 0); }
public void Init() { storage = new Storage("Тестовое место хранения", StorageType.DistributionCenter) { Id = 1 }; writeoffReason = new WriteoffReason("Тестовая причина списания") { Id = 2 }; var juridicalLegalForm = new LegalForm("ООО", EconomicAgentType.JuridicalPerson) { Id = 3 }; var juridicalPerson = new JuridicalPerson(juridicalLegalForm) { Id = 4 }; var juridicalPerson2 = new JuridicalPerson(juridicalLegalForm) { Id = 15 }; accountOrganization = new AccountOrganization("Тестовое юридическое лицо", "Тестовое юридическое лицо", juridicalPerson) { Id = 5 }; var provider = new Provider("Тестовый поставщик", new ProviderType("Тестовый тип поставщика"), ProviderReliability.Medium, 5) { Id = 6 }; var providerOrganization = new ProviderOrganization("Организация поставщика", "Организация поставщика", juridicalPerson2); var articleGroup = new ArticleGroup("Тестовая группа", "Тестовая группа"); var measureUnit = new MeasureUnit("шт.", "Штука", "123", 0) { Id = 1 }; var customDeclarationNumber = new String('0', 25); article = new Article("Тестовый товар А", articleGroup, measureUnit, true); providerContract = new ProviderContract(accountOrganization, providerOrganization, "Договор", "4645", DateTime.Now, DateTime.Now); provider.AddProviderContract(providerContract); user = new User(new Employee("Иван", "Иванов", "Иванович", new EmployeePost("Менеджер"), null), "Иванов Иван", "ivanov", "pa$$w0rd", new Team("Тестовая команда", null), null); receiptWaybill = new ReceiptWaybill("123АБВ", DateTime.Today.AddDays(1), storage, accountOrganization, provider, 1234.5M, 0M, new ValueAddedTax("18%", 18), providerContract, customDeclarationNumber, user, user, DateTime.Now); receiptWaybillRow = new ReceiptWaybillRow(article, 100, 1234.5M, receiptWaybill.PendingValueAddedTax); receiptWaybill.AddRow(receiptWaybillRow); writeoffWaybill = new WriteoffWaybill("123", DateTime.Today, storage, accountOrganization, writeoffReason, user, user, DateTime.Now); priceLists = new List <ArticleAccountingPrice>() { new ArticleAccountingPrice(article, 10M) }; }
/// <summary> /// Пересчет показателей закупок при отмене согласования накладной прихода. /// </summary> /// <param name="waybill">Накладная прихода. На момент вызова метода должна быть в состоянии "Согласована".</param> public void ReceiptWaybillApprovementCancelled(ReceiptWaybill waybill) { UpdateAcceptedIndicators(waybill, waybill.ApprovementDate.Value, -1, x => x.AreDivergencesAfterReceipt); UpdateApprovedIndicators(waybill, waybill.ApprovementDate.Value, -1, x => x.AreDivergencesAfterReceipt); if (!waybill.Rows.Any(x => x.AreDivergencesAfterReceipt)) { UpdateApprovedIndicators(waybill, waybill.ReceiptDate.Value, -1, x => !x.AreDivergencesAfterReceipt); } }
/// <summary> /// Установка закупочных цен в индикаторах по заданной приходной накладной из 0 в заданные значения (значения берутся из позиций приходной накладной) /// </summary> /// <param name="receiptWaybill">Приходная накладная</param> public void SetPurchaseCosts(ReceiptWaybill receiptWaybill) { var indicatorList = GetList(receiptWaybill.Id); var purchaseCostDictionary = receiptWaybill.Rows.ToDictionary(x => x.Id, x => x.PurchaseCost); foreach (var indicator in indicatorList) { indicator.PurchaseCostSum = Math.Round(purchaseCostDictionary[indicator.BatchId] * indicator.ReturnedCount, 6); } }
/// <summary> /// Установка закупочных цен по заданной приходной накладной из 0 в заданные значения (из позиций приходной накладной) /// </summary> /// <param name="receiptWaybill">Приходная накладная</param> public void SetPurchaseCosts(ReceiptWaybill receiptWaybill) { var indicatorList = GetList(receiptWaybill.Id); var purchaseCostDictionary = receiptWaybill.Rows.ToDictionary(x => x.Id, x => x.PurchaseCost); foreach (var indicator in indicatorList) { indicator.PurchaseCost = purchaseCostDictionary[indicator.BatchId]; } }
/// <summary> /// Пересчет финансовых показателей после окончательного согласования приходной накладной /// </summary> /// <param name="waybill">Приходная накладная</param> public void ReceiptWaybillApproved(ReceiptWaybill waybill) { // позиции с расхождениями при приемке var rows = waybill.Rows.Where(x => x.AreDivergencesAfterReceipt == true || x.PendingCount == 0); // расчет суммы в учетных ценах var currentAccountingSum = CalculateReceiptWaybillAccountingPriceSumByRows(rows); // расчет суммы в закупочных ценах var currentPurchaseCostSum = CalculateReceiptWaybillPurchaseCostSumByRows(rows); articleMovementFactualFinancialIndicatorService.Update(waybill.ApprovementDate.Value, null, null, waybill.AccountOrganization.Id, waybill.ReceiptStorage.Id, ArticleMovementOperationType.Receipt, waybill.Id, currentPurchaseCostSum, currentAccountingSum, 0); }
/// <summary> /// Измеение закупочных цен в индикаторах. /// </summary> /// <param name="receiptWaybill">Приходная накладная.</param> /// <param name="startDate">Дата, начиная с которой должны быть изменены индикаторы.</param> /// <param name="sign">Коэффициент, определяющий направление изменения индикатора. Принимает значение 1, или -1. При значении 1 индикатор будет увеличен, -1 — уменьшен.</param> private void UpdatePurchaseCosts(ReceiptWaybill receiptWaybill, DateTime startDate, short sign) { var indicatorList = purchaseIndicatorRepository.GetFrom(startDate.RoundToSeconds(), receiptWaybill.Curator.Id, receiptWaybill.ReceiptStorage.Id, receiptWaybill.Contract.Id, receiptWaybill.Contractor.Id, receiptWaybill.AccountOrganization.Id, receiptWaybill.ContractorOrganization.Id, receiptWaybillRepository.GetArticlesSubquery(receiptWaybill.Id)); var purchaseCostDictionary = receiptWaybill.Rows.ToDictionary(x => x.Article.Id, x => x.PurchaseCost); foreach (var row in receiptWaybill.Rows) { foreach (var indicator in indicatorList.Where(x => x.ArticleId == row.Article.Id)) { indicator.PurchaseCostSum += sign * Math.Round(purchaseCostDictionary[indicator.ArticleId] * row.CurrentCount, 6); } } }
/// <summary> /// Обновление показателя "отгруженных закупок". /// </summary> /// <param name="waybill">Накладная прихода.</param> /// <param name="date">Дата начала действия индикатора.</param> /// <param name="sign">Коэффициент, определяющий направление изменения индикатора. Принимает значение 1, или -1. При значении 1 индикатор будет увеличен, -1 — уменьшен.</param> /// <param name="rowsFilter">Фильтр позиций накладной. Должен возвращать true, если по этой позиции создавать индикатор и false в противном случае.</param> private void UpdateApprovedIndicators(ReceiptWaybill waybill, DateTime date, short sign, Func <ReceiptWaybillRow, bool> rowsFilter = null) { var approvedIndicators = new List <ApprovedPurchaseIndicator>(); ValidationUtils.Assert(sign == 1 || sign == -1, "Значение множителя может быть только 1 или -1."); var rows = rowsFilter != null?waybill.Rows.Where(x => rowsFilter(x)) : waybill.Rows; foreach (var item in rows) { approvedIndicators.Add(CreateApprovedPurchaseIndicator(date, item, sign)); } approvedPurchaseIndicatorService.Update(date, waybill.Curator.Id, waybill.ReceiptStorage.Id, waybill.Contract.Id, waybill.Contractor.Id, waybill.AccountOrganization.Id, waybill.ContractorOrganization.Id, approvedIndicators); }
/// <summary> /// Расчет стоимости накладной в закупочных ценах /// </summary> /// <param name="waybill">Приходная накладная</param> /// <param name="user">Пользователь</param> /// <param name="excludeDivergences">Исключить ли суммы по позициям с расхождениями</param> /// <returns>Сумма в учетных ценах. Если не удалось рассчитать, то null</returns> public decimal?CalcPurchaseCostSum(ReceiptWaybill waybill, User user, bool excludeDivergences) { decimal?result = 0; // если накладная принята с расхождениями (т.е. принята, но не согласована) if (waybill.ReceiptDate != null && !waybill.IsApproved) { // считаем сумму в УЦ для позиций без расхождений result = waybill.Rows.Where(x => !x.AreDivergencesAfterReceipt).Sum(x => Math.Round(x.CurrentCount * x.PurchaseCost, 2)); // если включаем позиции с расхождениями if (!excludeDivergences) { result += waybill.Rows.Where(x => x.AreDivergencesAfterReceipt).Sum(x => Math.Round(x.CurrentCount * x.PurchaseCost, 2)); } } else { result = waybill.Rows.Sum(x => Math.Round(x.CurrentCount * x.PurchaseCost, 2)); } return(result); }
/// <summary> /// Пересчет показателей закупок при отмене проводки накладной прихода. /// </summary> /// <param name="waybill">Накладная прихода. На момент вызова метода долна быть еще в состоянии "Проведена".</param> public void ReceiptWaybillAcceptanceCancelled(ReceiptWaybill waybill) { UpdateAcceptedIndicators(waybill, waybill.AcceptanceDate.Value, -1); }
/// <summary> /// Пересчитать суммы в закупочных ценах во всех затронутых индикаторах. Вызывается при установке цен в позициях данной приходной накладной (были нулевые) /// </summary> /// <param name="receiptWaybill">Приходная накладная (цены должны быть уже вычислены и записаны в нее)</param> public void SetPurchaseCosts(ReceiptWaybill receiptWaybill) { ChangePurchaseCosts(receiptWaybill, Decimal.One); }
/// <summary> /// Пересчет показателей закупок при согласовании накладной прихода. /// </summary> /// <param name="waybill">Накладная прихода. На момент вызова метода должна быть в состоянии "Согласована".</param> public void ReceiptWaybillApproved(ReceiptWaybill waybill) { UpdateAcceptedIndicators(waybill, waybill.ApprovementDate.Value, 1, x => x.AreDivergencesAfterReceipt); UpdateApprovedIndicators(waybill, waybill.ApprovementDate.Value, 1, x => x.AreDivergencesAfterReceipt); }
/// <summary> /// Пересчет показателей закупок при отмене приемки накладной прихода. /// </summary> /// <param name="waybill">Накладная прихода. На момент вызова метода должна быть в состоянии "Принята".</param> public void ReceiptWaybillReceiptCancelled(ReceiptWaybill waybill) { UpdateAcceptedIndicators(waybill, waybill.ReceiptDate.Value, 1, x => x.AreDivergencesAfterReceipt); UpdateApprovedIndicators(waybill, waybill.ReceiptDate.Value, -1, x => !x.AreDivergencesAfterReceipt); }
public void Init() { // инициализация IoC IoCInitializer.Init(); receiptWaybillRepository = Mock.Get(IoCContainer.Resolve <IReceiptWaybillRepository>()); receiptWaybillService = new ReceiptWaybillService(IoCContainer.Resolve <IArticleRepository>(), receiptWaybillRepository.Object, IoCContainer.Resolve <IMovementWaybillRepository>(), IoCContainer.Resolve <IExpenditureWaybillRepository>(), IoCContainer.Resolve <IStorageRepository>(), IoCContainer.Resolve <IUserRepository>(), IoCContainer.Resolve <IChangeOwnerWaybillRepository>(), IoCContainer.Resolve <IWriteoffWaybillRepository>(), IoCContainer.Resolve <IStorageService>(), IoCContainer.Resolve <IAccountOrganizationService>(), IoCContainer.Resolve <IProviderService>(), IoCContainer.Resolve <IProviderContractService>(), IoCContainer.Resolve <IValueAddedTaxService>(), IoCContainer.Resolve <IArticleMovementService>(), IoCContainer.Resolve <IArticlePriceService>(), IoCContainer.Resolve <IExactArticleAvailabilityIndicatorService>(), IoCContainer.Resolve <IIncomingAcceptedArticleAvailabilityIndicatorService>(), IoCContainer.Resolve <IArticleAccountingPriceIndicatorService>(), IoCContainer.Resolve <IArticleMovementOperationCountService>(), IoCContainer.Resolve <IOutgoingAcceptedFromExactArticleAvailabilityIndicatorService>(), IoCContainer.Resolve <IOutgoingAcceptedFromIncomingAcceptedArticleAvailabilityIndicatorService>(), IoCContainer.Resolve <IArticleMovementFactualFinancialIndicatorService>(), IoCContainer.Resolve <IFactualFinancialArticleMovementService>(), IoCContainer.Resolve <IAcceptedSaleIndicatorService>(), IoCContainer.Resolve <IShippedSaleIndicatorService>(), IoCContainer.Resolve <IReceiptedReturnFromClientIndicatorService>(), IoCContainer.Resolve <IAcceptedReturnFromClientIndicatorService>(), IoCContainer.Resolve <IReturnFromClientBySaleAcceptanceDateIndicatorService>(), IoCContainer.Resolve <IReturnFromClientBySaleShippingDateIndicatorService>(), IoCContainer.Resolve <IArticleRevaluationService>(), IoCContainer.Resolve <IArticlePurchaseService>(), IoCContainer.Resolve <IAcceptedPurchaseIndicatorService>(), IoCContainer.Resolve <IApprovedPurchaseIndicatorService>(), IoCContainer.Resolve <IArticleAvailabilityService>() ); var juridicalLegalForm = new LegalForm("ООО", EconomicAgentType.JuridicalPerson); var providerType = new ProviderType("Тестовый тип поставщика"); var articleGroup = new ArticleGroup("Бытовая техника", "Бытовая техника"); var measureUnit = new MeasureUnit("шт", "штука", "123", 0); var article = new Article("Пылесос", articleGroup, measureUnit, true) { Id = 1 }; priceLists = new List <ArticleAccountingPrice>() { new ArticleAccountingPrice(article, 100M) }; var provider = new Provider("Нейтральная организация", providerType, ProviderReliability.Medium, 5); var providerOrganization = new ProviderOrganization("Тестовое физическое лицо", "Тестовое физическое лицо", new JuridicalPerson(juridicalLegalForm)) { Id = 1 }; var accountOrganization = new AccountOrganization(@"ООО ""Юридическое лицо""", @"ООО ""Юридическое лицо""", new JuridicalPerson(juridicalLegalForm)) { Id = 2 }; provider.AddContractorOrganization(providerOrganization); var providerContract = new ProviderContract(accountOrganization, providerOrganization, "ABC", "123", DateTime.Now, DateTime.Today); provider.AddProviderContract(providerContract); role = new Role("Администратор"); role.AddPermissionDistribution(new PermissionDistribution(Permission.ReceiptWaybill_Delete_Row_Delete, PermissionDistributionType.All)); user = new User(new Employee("Иван", "Иванов", "Иванович", new EmployeePost("Менеджер"), null), "Иванов Иван", "ivanov", "pa$$w0rd", new Team("Тестовая команда", null), null); user.AddRole(role); createdBy = new User(new Employee("Олег", "Олегов", "Олегович", new EmployeePost("Менеджер"), null), "Олегов Олег", "olegov", "pa$$w0rd", new Team("Тестовая команда", null), null); createdBy.AddRole(role); acceptedBy = new User(new Employee("Петр", "Петров", "Петрович", new EmployeePost("Менеджер"), null), "Петров Петр", "petrov", "pa$$w0rd", new Team("Тестовая команда", null), null); acceptedBy.AddRole(role); receiptedBy = new User(new Employee("Николай", "Николаев", "Николаевия", new EmployeePost("Менеджер"), null), "Николаев Николай", "nikolaev", "pa$$w0rd", new Team("Тестовая команда", null), null); receiptedBy.AddRole(role); var customDeclarationNumber = new String('0', 25); receiptWaybill = new ReceiptWaybill("999999", DateTime.Today, new Storage("Третий склад", StorageType.DistributionCenter), accountOrganization, provider, 50, 0M, new ValueAddedTax("10%", 10), providerContract, customDeclarationNumber, user, createdBy, DateTime.Now); receiptWaybillRow = new ReceiptWaybillRow(article, 5, 50M, receiptWaybill.PendingValueAddedTax); receiptWaybill.AddRow(receiptWaybillRow); receiptWaybillList = new List <ReceiptWaybill> { receiptWaybill }; receiptWaybillRepository.Setup(x => x.Delete(It.IsAny <ReceiptWaybill>())).Callback <ReceiptWaybill>(waybill => receiptWaybillList.Remove(waybill)); }
public void Init() { receiptWaybillRepository = Mock.Get(IoCContainer.Resolve <IReceiptWaybillRepository>()); productionOrderRepository = Mock.Get(IoCContainer.Resolve <IProductionOrderRepository>()); productionOrderBatchRepository = Mock.Get(IoCContainer.Resolve <IProductionOrderBatchRepository>()); defaultProductionOrderStageRepository = Mock.Get(IoCContainer.Resolve <IDefaultProductionOrderStageRepository>()); taskRepository = Mock.Get(IoCContainer.Resolve <ITaskRepository>()); articleAccountingPriceIndicatorService = Mock.Get(IoCContainer.Resolve <IArticleAccountingPriceIndicatorService>()); productionOrderService_accessor = new Mock <ProductionOrderService_Accessor>(productionOrderRepository.Object, productionOrderBatchRepository.Object, receiptWaybillRepository.Object, taskRepository.Object, defaultProductionOrderStageRepository.Object); productionOrderService = new Mock <ProductionOrderService>(productionOrderRepository.Object, productionOrderBatchRepository.Object, receiptWaybillRepository.Object, taskRepository.Object, defaultProductionOrderStageRepository.Object); var juridicalLegalForm = new LegalForm("ООО", EconomicAgentType.JuridicalPerson); var providerType = new ProviderType("Тестовый тип поставщика"); var articleGroup = new ArticleGroup("Бытовая техника", "Бытовая техника"); var measureUnit = new MeasureUnit("шт", "штука", "123", 0); article1 = new Article("Пылесос", articleGroup, measureUnit, true) { Id = 1 }; article2 = new Article("Пылесос2", articleGroup, measureUnit, true) { Id = 2 }; article3 = new Article("Пылесос3", articleGroup, measureUnit, true) { Id = 3 }; priceLists = new List <ArticleAccountingPrice>() { new ArticleAccountingPrice(article1, 100M), new ArticleAccountingPrice(article2, 150M), new ArticleAccountingPrice(article3, 200M) }; var provider = new Provider("Нейтральная организация", providerType, ProviderReliability.Medium, 5); var providerOrganization = new ProviderOrganization("Тестовое физическое лицо", "Тестовое физическое лицо", new JuridicalPerson(juridicalLegalForm)) { Id = 1 }; var accountOrganization = new AccountOrganization(@"ООО ""Юридическое лицо""", @"ООО ""Юридическое лицо""", new JuridicalPerson(juridicalLegalForm)) { Id = 2 }; provider.AddContractorOrganization(providerOrganization); var providerContract = new ProviderContract(accountOrganization, providerOrganization, "ABC", "123", DateTime.Now, DateTime.Today); provider.AddProviderContract(providerContract); role = new Role("Администратор"); role.AddPermissionDistribution(new PermissionDistribution(Permission.ReceiptWaybill_Delete_Row_Delete, PermissionDistributionType.All)); user = new User(new Employee("Иван", "Иванов", "Иванович", new EmployeePost("Менеджер"), null), "Иванов Иван", "ivanov", "pa$$w0rd", new Team("Тестовая команда", null), null); user.AddRole(role); storage = new Storage("МХ", StorageType.TradePoint); storage.AddAccountOrganization(accountOrganization); producer = new Producer("producer", "organization", 5, user, false); var producerContract = new ProducerContract(accountOrganization, producer.Organization, "ABC", "123", DateTime.Now, DateTime.Today); currency = new Currency("755", "EUR", "Евро"); var stage1 = new ProductionOrderBatchStage_Accessor("1", ProductionOrderBatchStageType.Calculation, 1, false) { IsDefault = true }; var stage2 = new ProductionOrderBatchStage_Accessor("2", ProductionOrderBatchStageType.Closed, 0, false) { IsDefault = true }; var stage3 = new ProductionOrderBatchStage_Accessor("3", ProductionOrderBatchStageType.Closed, 0, false) { IsDefault = true }; var currentDateTime = DateTimeUtils.GetCurrentDateTime(); productionOrder = new ProductionOrder("ЗАКАЗ", producer, currency, (ProductionOrderBatchStage)stage1.Target, (ProductionOrderBatchStage)stage2.Target, (ProductionOrderBatchStage)stage3.Target, ProductionOrderArticleTransportingPrimeCostCalculationType.Weight, true, true, true, true, true, false, false, user, currentDateTime) { Storage = storage }; productionOrder.AddContract(producerContract); productionOrderBatch = productionOrder.Batches.FirstOrDefault(); manufacturer = new Manufacturer("Изготовитель"); producer.AddManufacturer(manufacturer); productionOrderBatchRow1 = new ProductionOrderBatchRow(article1, currency, 5M, 10M, 1.0M, new Country("Страна1", "686"), manufacturer) { Id = Guid.NewGuid() }; productionOrderBatchRow2 = new ProductionOrderBatchRow(article2, currency, 25M, 5M, 2.0M, new Country("Страна2", "686"), manufacturer) { Id = Guid.NewGuid() }; productionOrderBatchRow3 = new ProductionOrderBatchRow(article3, currency, 100M, 2M, 1.5M, new Country("Страна3", "686"), manufacturer) { Id = Guid.NewGuid() }; productionOrderBatch.AddRow(productionOrderBatchRow1); productionOrderBatch.AddRow(productionOrderBatchRow2); productionOrderBatch.AddRow(productionOrderBatchRow3); var customDeclarationNumber = new String('0', 25); receiptWaybill_accessor = new ReceiptWaybill_Accessor(productionOrderBatch, "999999", DateTime.Today, new ValueAddedTax("10%", 10), customDeclarationNumber, user, user, DateTime.Now); receiptWaybill = (ReceiptWaybill)receiptWaybill_accessor.Target; receiptWaybillRow1 = new ReceiptWaybillRow(article1, 10M, 0M, receiptWaybill.PendingValueAddedTax) { Id = Guid.NewGuid() }; receiptWaybill.AddRow(receiptWaybillRow1); productionOrderBatch.Rows.Where(x => x.Article == article1).FirstOrDefault().ReceiptWaybillRow = receiptWaybillRow1; receiptWaybillRow2 = new ReceiptWaybillRow(article2, 5M, 0M, receiptWaybill.PendingValueAddedTax) { Id = Guid.NewGuid() }; receiptWaybill.AddRow(receiptWaybillRow2); productionOrderBatch.Rows.Where(x => x.Article == article2).FirstOrDefault().ReceiptWaybillRow = receiptWaybillRow2; receiptWaybillRow3 = new ReceiptWaybillRow(article3, 2M, 0M, receiptWaybill.PendingValueAddedTax) { Id = Guid.NewGuid() }; receiptWaybill.AddRow(receiptWaybillRow3); productionOrderBatch.Rows.Where(x => x.Article == article3).FirstOrDefault().ReceiptWaybillRow = receiptWaybillRow3; receiptWaybillList = new List <ReceiptWaybill> { receiptWaybill }; receiptWaybillRepository.Setup(x => x.Delete(It.IsAny <ReceiptWaybill>())).Callback <ReceiptWaybill>(waybill => receiptWaybillList.Remove(waybill)); receiptWaybill.Accept(priceLists, user, DateTime.Now); receiptWaybillRow1.ReceiptedCount = receiptWaybillRow1.PendingCount; receiptWaybillRow1.ProviderCount = receiptWaybillRow1.PendingCount; receiptWaybillRow1.ProviderSum = 0M; receiptWaybillRow2.ReceiptedCount = receiptWaybillRow2.PendingCount; receiptWaybillRow2.ProviderCount = receiptWaybillRow2.PendingCount; receiptWaybillRow2.ProviderSum = 0M; receiptWaybillRow3.ReceiptedCount = receiptWaybillRow3.PendingCount; receiptWaybillRow3.ProviderCount = receiptWaybillRow3.PendingCount; receiptWaybillRow3.ProviderSum = 0M; }
/// <summary> /// Уменьшение закупочных цен в индикаторах по заданной приходной накладной на заданные значения(значения берутся из позиций приходной накладной). /// </summary> /// <param name="receiptWaybill">Приходная накладная.</param> /// <param name="startDate">Дата, начиная с которой должны быть изменены индикаторы.</param> public void ResetPurchaseCosts(ReceiptWaybill receiptWaybill, DateTime startDate) { UpdatePurchaseCosts(receiptWaybill, startDate, -1); }
public void WaybillFinalizationCancelled(ReceiptWaybill waybill) { articleMovementOperationCountIndicatorService.DecrementIndicator(waybill.ReceiptDate.Value, ArticleMovementOperationType.Receipt, waybill.ReceiptStorage.Id); }
/// <summary> /// Пересчитать суммы в закупочных ценах во всех затронутых индикаторах. Вызывается при обнулении цен в позициях данной приходной накладной /// </summary> /// <param name="receiptWaybill">Приходная накладная</param> public void ResetPurchaseCosts(ReceiptWaybill receiptWaybill) { ChangePurchaseCosts(receiptWaybill, Decimal.MinusOne); }
/// <summary> /// Пересчитать суммы в закупочных ценах во всех затронутых индикаторах. /// </summary> /// <param name="receiptWaybill">Приходная накладная, содержащая закупочные цены</param> /// <param name="sign">Знак (+1 или -1), с которым применяются данные закупочные цены (они возникают или обнуляются)</param> private void ChangePurchaseCosts(ReceiptWaybill receiptWaybill, decimal sign) { IEnumerable <Guid> movementWaybillIdList, writeoffWaybillIdList, expenditureWaybillIdList, returnFromClientWaybillIdList; IEnumerable <MovementWaybillRow> movementWaybillRowList; IEnumerable <WriteoffWaybillRow> writeoffWaybillRowList; IEnumerable <ExpenditureWaybillRow> expenditureWaybillRowList; IEnumerable <ReturnFromClientWaybillRow> returnFromClientWaybillRowList; DateTime startDate; // Получаем список индикаторов, непосредственно отражающих действия с накладными, имеющими позиции по заданному приходу var actionIndicatorList = articleMovementFactualFinancialIndicatorRepository.GetIndicatorListForReceiptWaybill(receiptWaybill.Id, out movementWaybillIdList, out movementWaybillRowList, out writeoffWaybillIdList, out writeoffWaybillRowList, out expenditureWaybillIdList, out expenditureWaybillRowList, out returnFromClientWaybillIdList, out returnFromClientWaybillRowList, out startDate); // Создаем словарь старых закупочных цен (ключ - код показателя, значение - старая ЗЦ, если нет такого элемента, ЗЦ не менялась) var oldPurchaseCostSumList = new Dictionary <Guid, decimal>(); // 321 Так как проверяется только наличие показателя в данном списке (по id), можно бы сделать возвращаемое значение списком id - и облегчить запрос? // Если это не будет противоречить рефакторингу, о котором написано ниже (отобрать индикаторы во 2 список по одним ключам из 5-ти значений из списка actionIndicatorList) if (!actionIndicatorList.Any()) { return; } // Приход всегда один. И операция по нему одна - приемка без расхождений. И первая по времени var receiptWaybillRowDictionary = receiptWaybill.Rows.ToDictionary(x => x.Id); // Вычисляем суммы в ЗЦ, на которые изменились суммы затронутых накладных, и помещаем в Dictionary var purchaseCostChangeSumList = new DynamicDictionary <Guid, decimal>(); purchaseCostChangeSumList[receiptWaybill.Id] = receiptWaybillRowDictionary.Sum(x => Math.Round(x.Value.PendingCount * x.Value.PurchaseCost, 6)); foreach (var movementWaybillRow in movementWaybillRowList) { purchaseCostChangeSumList[movementWaybillRow.MovementWaybill.Id] += Math.Round(movementWaybillRow.MovingCount * receiptWaybillRowDictionary[movementWaybillRow.ReceiptWaybillRow.Id].PurchaseCost, 6); } foreach (var writeoffWaybillRow in writeoffWaybillRowList) { purchaseCostChangeSumList[writeoffWaybillRow.WriteoffWaybill.Id] += Math.Round(writeoffWaybillRow.WritingoffCount * receiptWaybillRowDictionary[writeoffWaybillRow.ReceiptWaybillRow.Id].PurchaseCost, 6); } foreach (var expenditureWaybillRow in expenditureWaybillRowList) { purchaseCostChangeSumList[expenditureWaybillRow.SaleWaybill.Id] += Math.Round(expenditureWaybillRow.SellingCount * receiptWaybillRowDictionary[expenditureWaybillRow.ReceiptWaybillRow.Id].PurchaseCost, 6); } foreach (var returnFromClientWaybillRow in returnFromClientWaybillRowList) { purchaseCostChangeSumList[returnFromClientWaybillRow.ReturnFromClientWaybill.Id] += Math.Round(returnFromClientWaybillRow.ReturnCount * receiptWaybillRowDictionary[returnFromClientWaybillRow.ReceiptWaybillRow.Id].PurchaseCost, 6); } // Сделана проверка только на получателя! (Ведь пересчитывать сумму в ЗЦ на конкретном месте хранения следует только с момента, // когда данное МХ появляется в получателе (RecipientStorageId) - т.е. когда на данное МХ приходит товар, приходом, перемещением или возвратом) var storageList = actionIndicatorList.Select(x => x.Value.RecipientStorageId).Distinct().Where(x => x != null).Select(x => x.Value); // Словарь дельт (изменений суммы) в ЗЦ по всем ключам по отношению к ситуации до пересчета // Ключ (см. сущность показателя) есть код организации-отправителя, код МХ-отправителя, код организации-получателя, код МХ-получателя, тип операции товародвижения var storagePurchaseCostChangeSumDictionary = new DynamicDictionary <int, DynamicDictionary <short, DynamicDictionary <int, DynamicDictionary <short, DynamicDictionary <ArticleMovementOperationType, decimal> > > > >(); // Возможно, можно отбирать индикаторы во 2-й список по одним ключам из 5-ти значений из списка actionIndicatorList, // а не тянуть все для данного МХ. Но этот вопрос требует дополнительных исследований // Получаем список всех индикаторов, затронутых данными действиями (туда войдут и все из первого списка) var indicatorList = articleMovementFactualFinancialIndicatorRepository.GetIndicatorsListAfterDate(storageList, startDate); var indicatorDictionary = indicatorList.ToDictionary <ArticleMovementFactualFinancialIndicator, Guid>(x => x.Id); // Перебираем индикаторы по времени начала действия foreach (var indicator in indicatorList.OrderBy(x => x.StartDate)) { // Из-за текущей системы проектирования показателей в БД остается строка даже для отмененной операции. При этом нет никакого признака, что операция отменена. // Поэтому можно брать разницу между данным показателем и предыдущим, и если она равна 0 - то игнорировать его. // Надо отметить, что при 0-х УЦ и ЗЦ может статься, что показатель не приращивает ни одно из значений, но не "отменен". // Этого тоже надо в будущем при перепроектировании избежать. decimal purchaseCostChangeSum, accountingPriceChangeSum, salePriceChangeSum; // Если показатель имеет предыдущий, вычисляем разность между ними во всех видах цен. if (indicator.PreviousId.HasValue) { ArticleMovementFactualFinancialIndicator previousIndicator; // Предыдущий может не попасть в выборку indicatorDictionary (если он был создан давно). // Если же попадает, в indicatorDictionary быстро находим по ключу показатель с заданным Id. if (indicatorDictionary.ContainsKey(indicator.PreviousId.Value)) { previousIndicator = indicatorDictionary[indicator.PreviousId.Value]; } else { previousIndicator = articleMovementFactualFinancialIndicatorRepository.GetById(indicator.PreviousId.Value); ValidationUtils.NotNull(previousIndicator, "Индикатор не найден по своему идентификатору."); } decimal previousIndicatorOldPurchaseCostSum = oldPurchaseCostSumList.ContainsKey(previousIndicator.Id) ? oldPurchaseCostSumList[previousIndicator.Id] : previousIndicator.PurchaseCostSum; purchaseCostChangeSum = indicator.PurchaseCostSum - previousIndicatorOldPurchaseCostSum; accountingPriceChangeSum = indicator.AccountingPriceSum - previousIndicator.AccountingPriceSum; salePriceChangeSum = indicator.SalePriceSum - previousIndicator.SalePriceSum; } else { purchaseCostChangeSum = indicator.PurchaseCostSum; accountingPriceChangeSum = indicator.AccountingPriceSum; salePriceChangeSum = indicator.SalePriceSum; } // Если показатель дает нулевое приращение - например, он остался на месте показателя по принятию накладной после отмены принятия - игнорируем его: // не изменяем из-за него дельту по его ключу (но, как и для всех, пересчитываем его сумму в ЗЦ по существующей дельте) if (purchaseCostChangeSum != 0M || accountingPriceChangeSum != 0M || salePriceChangeSum != 0M) { // При нахождении данного показателя в списке непосредственно отражающих действия с накладными - изменяем дельту по данному ключу if (actionIndicatorList.ContainsKey(indicator.Id)) { decimal waybillPurchaseCostChangeSum = purchaseCostChangeSumList[indicator.WaybillId] * sign; storagePurchaseCostChangeSumDictionary [indicator.SenderId ?? 0] [indicator.SenderStorageId ?? (short)0] [indicator.RecipientId ?? 0] [indicator.RecipientStorageId ?? (short)0] [indicator.ArticleMovementOperationType] += waybillPurchaseCostChangeSum; } } // Если дельта по данному ключу не равна 0, меняем значение индикатора decimal indicatorPurchaseCostChangeSum = storagePurchaseCostChangeSumDictionary[indicator.SenderId ?? 0] [indicator.SenderStorageId ?? (short)0] [indicator.RecipientId ?? 0] [indicator.RecipientStorageId ?? (short)0] [indicator.ArticleMovementOperationType]; if (indicatorPurchaseCostChangeSum != 0M) { oldPurchaseCostSumList[indicator.Id] = indicator.PurchaseCostSum; indicator.PurchaseCostSum += indicatorPurchaseCostChangeSum; } } }
/// <summary> /// Сброс закупочных цен в индикаторах по заданной приходной накладной в 0 /// </summary> /// <param name="receiptWaybill">Приходная накладная</param> public void ResetPurchaseCosts(ReceiptWaybill receiptWaybill) { GetList(receiptWaybill.Id).ToList().ForEach(x => x.PurchaseCostSum = 0M); }
public void Init() { articleGroup = new ArticleGroup("Бытовая техника", "Бытовая техника"); articleGroup.SalaryPercent = 15; articleGroup.Id = 8; measureUnit = new MeasureUnit("шт.", "Штука", "123", 0); measureUnit.Id = 17; articleA = new Article("Пылесос", articleGroup, measureUnit, true) { Id = 29, Number = "ПЫЛ" }; articleB = new Article("Холодильник", articleGroup, measureUnit, true) { Id = 38, Number = "ХО-1" }; articleC = new Article("Плита газовая", articleGroup, measureUnit, true) { Id = 48, Number = "ПГ1" }; articleAccountingPriceA1 = new ArticleAccountingPrice(articleA, 1M); articleAccountingPriceA2 = new ArticleAccountingPrice(articleA, 1001M); articleAccountingPriceA3 = new ArticleAccountingPrice(articleA, 1192.45M); articleAccountingPriceB = new ArticleAccountingPrice(articleB, 150M); articleAccountingPriceC = new ArticleAccountingPrice(articleC, 180M); articleAccountingPriceWrongListOnlyA = new List <ArticleAccountingPrice>(); articleAccountingPriceWrongListOnlyA.Add(articleAccountingPriceA1); articleAccountingPriceWrongListOnlyA.Add(articleAccountingPriceA2); articleAccountingPriceWrongListOnlyA.Add(articleAccountingPriceA3); articleAccountingPriceCorrectList1 = new List <ArticleAccountingPrice>(); articleAccountingPriceCorrectList1.Add(articleAccountingPriceA2); articleAccountingPriceCorrectList1.Add(articleAccountingPriceB); articleAccountingPriceCorrectList1.Add(articleAccountingPriceC); storage1 = new Storage("Торговая точка номер 1", StorageType.TradePoint); storage2 = new Storage("Доп. склад северный", StorageType.ExtraStorage); storage3 = new Storage("Торговая точка номер 2", StorageType.TradePoint); storageList1 = new List <Storage>(); storageList1.Add(storage1); storageList1.Add(storage2); storageList1.Add(storage3); var juridicalLegalForm = new LegalForm("ООО", EconomicAgentType.JuridicalPerson); var physicalLegalForm = new LegalForm("ИП", EconomicAgentType.PhysicalPerson); juridicalPerson = new JuridicalPerson(juridicalLegalForm) { Id = 1 }; physicalPerson = new PhysicalPerson(physicalLegalForm) { Id = 2 }; accountOrganization = new AccountOrganization("Тестовое юридическое лицо", "Тестовое юридическое лицо", juridicalPerson) { Id = 1 }; providerOrganization = new ProviderOrganization("Тестовое физическое лицо", "Тестовое физическое лицо", physicalPerson) { Id = 2 }; provider = new Provider("Тестовый поставщик", new ProviderType("Тестовый тип поставщика"), ProviderReliability.Medium, 5); provider.AddContractorOrganization(providerOrganization); providerContract = new ProviderContract(accountOrganization, providerOrganization, "ABC", "123", DateTime.Now, DateTime.Today); provider.AddProviderContract(providerContract); user = new User(new Employee("Иван", "Иванов", "Иванович", new EmployeePost("Менеджер"), null), "Иванов Иван", "ivanov", "pa$$w0rd", new Team("Тестовая команда", null), null); var customDeclarationNumber = new String('0', 25); receiptWaybill = new ReceiptWaybill("123АБВ", DateTime.Today, storage1, accountOrganization, provider, 100.05M, 0M, new ValueAddedTax("18%", 18), providerContract, customDeclarationNumber, user, user, DateTime.Now); priceRule = new AccountingPriceCalcRule( new AccountingPriceCalcByPurchaseCost(PurchaseCostDeterminationRuleType.ByMinimalPurchaseCost, new MarkupPercentDeterminationRule(10))); digitRule = new LastDigitCalcRule(LastDigitCalcRuleType.SetCustom); user = new User(new Employee("Иван", "Иванов", "Иванович", new EmployeePost("Менеджер"), null), "Иванов Иван", "ivanov", "pa$$w0rd", new Team("Тестовая команда", null), null); }