/* * * (c) Copyright Ascensio System Limited 2010-2018 * * This program is freeware. You can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html). * In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that * Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights. * * THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR * FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html * * You can contact Ascensio System SIA by email at sales@onlyoffice.com * * The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display * Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3. * * Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains * relevant author attributions when distributing the software. If the display of the logo in its graphic * form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE" * in every copy of the program you distribute. * Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks. * */ using ASC.Api.Core; using ASC.CRM.ApiModels; using ASC.Api.Documents; using ASC.Common.Web; using ASC.Core; using ASC.CRM.Classes; using ASC.CRM.Core; using ASC.CRM.Core.Entities; using ASC.CRM.Core.Enums; using ASC.CRM.Resources; using ASC.MessagingSystem; using ASC.Web.Api.Routing; using ASC.Web.CRM.Classes; using Microsoft.AspNetCore.Mvc; using System; using System.Collections.Generic; using System.Linq; using ASC.Api.CRM; using ASC.CRM.Core.Dao; using ASC.Web.CRM.Services.NotifyService; using ASC.Web.Core.Users; using ASC.Core.Common.Settings; namespace ASC.CRM.Api { public class InvoicesController : BaseApiController { public InvoicesController(CRMSecurity cRMSecurity, DaoFactory daoFactory, ApiContext apiContext, MessageTarget messageTarget, MessageService messageService, ContactDtoHelper contactBaseDtoHelper, InvoiceDtoHelper invoiceDtoHelper, ApiDateTimeHelper apiDateTimeHelper, SettingsManager settingsManager, FileWrapperHelper fileWrapperHelper, PdfCreator pdfCreator, CurrencyInfoDtoHelper currencyInfoDtoHelper, InvoiceBaseDtoHelper invoiceBaseDtoHelper, InvoiceItemDtoHelper invoiceItemDtoHelper, Global global, InvoiceLineDtoHelper invoiceLineDtoHelper, InvoiceTaxDtoHelper invoiceTaxDtoHelper) : base(daoFactory, cRMSecurity) { ApiContext = apiContext; MessageTarget = messageTarget; MessageService = messageService; ContactDtoHelper = contactBaseDtoHelper; InvoiceDtoHelper = invoiceDtoHelper; ApiDateTimeHelper = apiDateTimeHelper; SettingsManager = settingsManager; PdfCreator = pdfCreator; FileWrapperHelper = fileWrapperHelper; CurrencyInfoDtoHelper = currencyInfoDtoHelper; InvoiceBaseDtoHelper = invoiceBaseDtoHelper; InvoiceItemDtoHelper = invoiceItemDtoHelper; Global = global; InvoiceLineDtoHelper = invoiceLineDtoHelper; InvoiceTaxDtoHelper = invoiceTaxDtoHelper; } public InvoiceTaxDtoHelper InvoiceTaxDtoHelper { get; } public InvoiceLineDtoHelper InvoiceLineDtoHelper { get; } public Global Global { get; } public InvoiceItemDtoHelper InvoiceItemDtoHelper { get; } public InvoiceBaseDtoHelper InvoiceBaseDtoHelper { get; } public CurrencyInfoDtoHelper CurrencyInfoDtoHelper { get; } public FileWrapperHelper FileWrapperHelper { get; } public PdfCreator PdfCreator { get; } public SettingsManager SettingsManager { get; } public ApiDateTimeHelper ApiDateTimeHelper { get; } public InvoiceDtoHelper InvoiceDtoHelper { get; } public ContactDtoHelper ContactDtoHelper { get; } private ApiContext ApiContext { get; } public MessageService MessageService { get; } public MessageTarget MessageTarget { get; } /// /// Returns the detailed information about the invoice with the ID specified in the request /// /// Invoice ID /// Get invoice by ID /// Invoices /// Invoice [Read(@"invoice/{invoiceid:int}")] public InvoiceDto GetInvoiceByID(int invoiceid) { if (invoiceid <= 0) throw new ArgumentException(); var invoice = DaoFactory.GetInvoiceDao().GetByID(invoiceid); if (invoice == null) throw new ItemNotFoundException(); if (!CRMSecurity.CanAccessTo(invoice)) { throw CRMSecurity.CreateSecurityException(); } return InvoiceDtoHelper.Get(invoice); } /// /// Returns the detailed information about the invoice sample /// /// Get invoice sample /// Invoices /// Invoice [Read(@"invoice/sample")] public InvoiceDto GetInvoiceSample() { var sample = InvoiceDto.GetSample(); sample.Number = DaoFactory.GetInvoiceDao().GetNewInvoicesNumber(); sample.Terms = DaoFactory.GetInvoiceDao().GetSettings().Terms ?? string.Empty; sample.IssueDate = ApiDateTimeHelper.Get(DateTime.UtcNow); sample.DueDate = ApiDateTimeHelper.Get(DateTime.UtcNow.AddDays(30)); sample.CreateOn = ApiDateTimeHelper.Get(DateTime.UtcNow); sample.Currency = CurrencyInfoDtoHelper.Get(SettingsManager.Load().DefaultCurrency); sample.InvoiceLines.First().Quantity = 1; return sample; } /// /// Returns the json data of the invoice with the ID specified in the request /// /// Invoice ID /// Get invoice json data /// Invoices /// Json Data [Read(@"invoice/jsondata/{invoiceid:int}")] public string GetInvoiceJsonData(int invoiceid) { var invoice = DaoFactory.GetInvoiceDao().GetByID(invoiceid); if (invoice == null) throw new ItemNotFoundException(); if (!CRMSecurity.CanAccessTo(invoice)) { throw CRMSecurity.CreateSecurityException(); } return invoice.JsonData; } /// /// Returns the list of invoices matching the creteria specified in the request /// /// Invoice status /// Invoice issue date from /// Invoice issue date to /// Invoice due date from /// Invoice due date to /// Invoice entity type /// Invoice entity ID /// Invoice currency /// Get invoice list /// Invoices /// Invoice list [Read(@"invoice/filter")] public IEnumerable GetInvoices( InvoiceStatus? status, ApiDateTime issueDateFrom, ApiDateTime issueDateTo, ApiDateTime dueDateFrom, ApiDateTime dueDateTo, String entityType, int entityid, String currency ) { if (!String.IsNullOrEmpty(entityType) && !( String.Compare(entityType, "contact", true) == 0 || String.Compare(entityType, "opportunity", true) == 0 || String.Compare(entityType, "case", true) == 0)) throw new ArgumentException(); IEnumerable result; InvoiceSortedByType sortBy; OrderBy invoiceOrderBy; var searchString = ApiContext.FilterValue; if (InvoiceSortedByType.TryParse(ApiContext.SortBy, true, out sortBy)) { invoiceOrderBy = new OrderBy(sortBy, !ApiContext.SortDescending); } else if (String.IsNullOrEmpty(ApiContext.SortBy)) { invoiceOrderBy = new OrderBy(InvoiceSortedByType.Number, true); } else { invoiceOrderBy = null; } var fromIndex = (int)ApiContext.StartIndex; var count = (int)ApiContext.Count; if (invoiceOrderBy != null) { result = ToListInvoiceBaseDtos( DaoFactory.GetInvoiceDao().GetInvoices( searchString, status, issueDateFrom, issueDateTo, dueDateFrom, dueDateTo, ToEntityType(entityType), entityid, currency, fromIndex, count, invoiceOrderBy)); ApiContext.SetDataPaginated(); ApiContext.SetDataFiltered(); ApiContext.SetDataSorted(); } else { result = ToListInvoiceBaseDtos( DaoFactory.GetInvoiceDao().GetInvoices( searchString, status, issueDateFrom, issueDateTo, dueDateFrom, dueDateTo, ToEntityType(entityType), entityid, currency, 0, 0, null)); } int totalCount; if (result.Count() < count) { totalCount = fromIndex + result.Count(); } else { totalCount = DaoFactory.GetInvoiceDao().GetInvoicesCount( searchString, status, issueDateFrom, issueDateTo, dueDateFrom, dueDateTo, ToEntityType(entityType), entityid, currency); } ApiContext.SetTotalCount(totalCount); return result; } /// /// Returns the list of all invoices associated with the entity with the ID and type specified in the request /// /// Invoice entity type /// Invoice entity ID /// Get entity invoices /// Invoices /// Invoice list [Read(@"{entityType:regex(contact|person|company|opportunity)}/invoicelist/{entityid:int}")] public IEnumerable GetEntityInvoices(String entityType, int entityid) { if (String.IsNullOrEmpty(entityType) || entityid <= 0) throw new ArgumentException(); return ToListInvoiceBaseDtos(DaoFactory.GetInvoiceDao().GetEntityInvoices(ToEntityType(entityType), entityid)); } /// /// Updates the status of invoices with the IDs specified in the request /// /// Invoice ID list /// Status /// Update invoice group status /// Invoices /// KeyValuePair of Invoices and InvoiceItems [Update(@"invoice/status/{status:int}")] public KeyValuePair, IEnumerable> UpdateInvoiceBatchStatus( int[] invoiceids, InvoiceStatus status ) { if (invoiceids == null || !invoiceids.Any()) throw new ArgumentException(); var oldInvoices = DaoFactory.GetInvoiceDao().GetByID(invoiceids).Where(CRMSecurity.CanAccessTo).ToList(); var updatedInvoices = DaoFactory.GetInvoiceDao().UpdateInvoiceBatchStatus(oldInvoices.ToList().Select(i => i.ID).ToArray(), status); // detect what really changed var realUpdatedInvoices = updatedInvoices .Select(t => oldInvoices.FirstOrDefault(x => x.ID == t.ID && x.Status != t.Status)) .Where(inv => inv != null) .ToList(); if (realUpdatedInvoices.Any()) { MessageService.Send(MessageAction.InvoicesUpdatedStatus, MessageTarget.Create(realUpdatedInvoices.Select(x => x.ID)), realUpdatedInvoices.Select(x => x.Number), status.ToLocalizedString()); } var invoiceItemsUpdated = new List(); if (status == InvoiceStatus.Sent || status == InvoiceStatus.Rejected) { var invoiceItemsAll = DaoFactory.GetInvoiceItemDao().GetAll(); var invoiceItemsWithTrackInventory = invoiceItemsAll.Where(item => item.TrackInventory).ToList(); if (status == InvoiceStatus.Sent && invoiceItemsWithTrackInventory != null && invoiceItemsWithTrackInventory.Count != 0) { foreach (var inv in updatedInvoices) { if (inv.Status == InvoiceStatus.Sent) { //could be changed var oldInv = oldInvoices.FirstOrDefault(i => i.ID == inv.ID); if (oldInv != null && oldInv.Status == InvoiceStatus.Draft) { //was changed to Sent var invoiceLines = DaoFactory.GetInvoiceLineDao().GetInvoiceLines(inv.ID); foreach (var line in invoiceLines) { var item = invoiceItemsWithTrackInventory.FirstOrDefault(ii => ii.ID == line.InvoiceItemID); if (item != null) { item.StockQuantity -= line.Quantity; DaoFactory.GetInvoiceItemDao().SaveOrUpdateInvoiceItem(item); var oldItem = invoiceItemsUpdated.Find(i => i.ID == item.ID); if (oldItem != null) { invoiceItemsUpdated.Remove(oldItem); } invoiceItemsUpdated.Add(item); } } } } } } if (status == InvoiceStatus.Rejected && invoiceItemsWithTrackInventory != null && invoiceItemsWithTrackInventory.Count != 0) { foreach (var inv in updatedInvoices) { if (inv.Status == InvoiceStatus.Rejected) { //could be changed var oldInv = oldInvoices.FirstOrDefault(i => i.ID == inv.ID); if (oldInv != null && oldInv.Status == InvoiceStatus.Sent) { //was changed from Sent to Rejectes var invoiceLines = DaoFactory.GetInvoiceLineDao().GetInvoiceLines(inv.ID); foreach (var line in invoiceLines) { var item = invoiceItemsWithTrackInventory.FirstOrDefault(ii => ii.ID == line.InvoiceItemID); if (item != null) { item.StockQuantity += line.Quantity; DaoFactory.GetInvoiceItemDao().SaveOrUpdateInvoiceItem(item); var oldItem = invoiceItemsUpdated.Find(i => i.ID == item.ID); if (oldItem != null) { invoiceItemsUpdated.Remove(oldItem); } invoiceItemsUpdated.Add(item); } } } } } } } var listInvoiceBaseDtos = ToListInvoiceBaseDtos(updatedInvoices); return new KeyValuePair, IEnumerable>(listInvoiceBaseDtos, invoiceItemsUpdated.ConvertAll(i => InvoiceItemDtoHelper.Get(i))); } /// /// Delete the invoice with the ID specified in the request /// /// Invoice ID /// Delete invoice /// Invoices /// Invoice [Delete(@"invoice/{invoiceid:int}")] public InvoiceBaseDto DeleteInvoice(int invoiceid) { if (invoiceid <= 0) throw new ArgumentException(); var invoice = DaoFactory.GetInvoiceDao().DeleteInvoice(invoiceid); if (invoice == null) throw new ItemNotFoundException(); MessageService.Send(MessageAction.InvoiceDeleted, MessageTarget.Create(invoice.ID), invoice.Number); return InvoiceBaseDtoHelper.Get(invoice); } /// /// Deletes the group of invoices with the IDs specified in the request /// /// Invoice ID list /// Delete invoice group /// Invoices /// Invoice list [Delete(@"invoice")] public IEnumerable DeleteBatchInvoices(IEnumerable invoiceids) { if (invoiceids == null || !invoiceids.Any()) throw new ArgumentException(); var invoices = DaoFactory.GetInvoiceDao().DeleteBatchInvoices(invoiceids.ToArray()); MessageService.Send(MessageAction.InvoicesDeleted, MessageTarget.Create(invoices.Select(x => x.ID)), invoices.Select(x => x.Number)); return ToListInvoiceBaseDtos(invoices); } /// /// Creates the invoice with the parameters (contactId, consigneeId, etc.) specified in the request /// /// Invoice number /// Invoice issue date /// Invoice template type /// Invoice contact ID /// Invoice consignee ID /// Invoice entity ID /// Invoice billing address ID /// Invoice delivery address ID /// Invoice due date /// Invoice language /// Invoice currency /// Invoice exchange rate /// Invoice purchase order number /// Invoice terms /// Invoice description /// Invoice lines list /// Create invoice /// Invoices /// Invoice /// /// /// [Create(@"invoice")] public InvoiceDto CreateInvoice( CreateOrUpdateInvoiceInDto inDto ) { string number = inDto.Number; ApiDateTime issueDate = inDto.IssueDate; int templateType = inDto.TemplateType; int contactId = inDto.ContactId; int consigneeId = inDto.ConsigneeId; int entityId = inDto.EntityId; int billingAddressID = inDto.BillingAddressID; int deliveryAddressID = inDto.DeliveryAddressID; ApiDateTime dueDate = inDto.DueDate; string language = inDto.Language; string currency = inDto.Currency; decimal exchangeRate = inDto.ExchangeRate; string purchaseOrderNumber = inDto.PurchaseOrderNumber; string terms = inDto.Terms; string description = inDto.Description; IEnumerable invoiceLines = inDto.InvoiceLines; var invoiceLinesList = invoiceLines != null ? invoiceLines.ToList() : new List(); if (!invoiceLinesList.Any() || !IsLinesForInvoiceCorrect(invoiceLinesList)) throw new ArgumentException(); var invoice = new Invoice { Status = InvoiceStatus.Draft, Number = number, IssueDate = issueDate, TemplateType = (InvoiceTemplateType)templateType, ContactID = contactId, ConsigneeID = consigneeId, EntityType = EntityType.Opportunity, EntityID = entityId, DueDate = dueDate, Language = language, Currency = !String.IsNullOrEmpty(currency) ? currency.ToUpper() : null, ExchangeRate = exchangeRate, PurchaseOrderNumber = purchaseOrderNumber, Terms = terms, Description = description }; CRMSecurity.DemandCreateOrUpdate(invoice); if (billingAddressID > 0) { var address = DaoFactory.GetContactInfoDao().GetByID(billingAddressID); if (address == null || address.InfoType != ContactInfoType.Address || address.Category != (int)AddressCategory.Billing || address.ContactID != contactId) throw new ArgumentException(); } if (deliveryAddressID > 0) { var address = DaoFactory.GetContactInfoDao().GetByID(deliveryAddressID); if (address == null || address.InfoType != ContactInfoType.Address || address.Category != (int)AddressCategory.Postal || address.ContactID != consigneeId) throw new ArgumentException(); } invoice.ID = DaoFactory.GetInvoiceDao().SaveOrUpdateInvoice(invoice); CreateInvoiceLines(invoiceLinesList, invoice); DaoFactory.GetInvoiceDao().UpdateInvoiceJsonData(invoice, billingAddressID, deliveryAddressID); return InvoiceDtoHelper.Get(invoice); } private bool IsLinesForInvoiceCorrect(List invoiceLines) { foreach (var line in invoiceLines) { if (line.InvoiceItemID <= 0 || line.Quantity < 0 || line.Price < 0 || line.Discount < 0 || line.Discount > 100 || line.InvoiceTax1ID < 0 || line.InvoiceTax2ID < 0) return false; if (!DaoFactory.GetInvoiceItemDao().IsExist(line.InvoiceItemID)) return false; if (line.InvoiceTax1ID > 0 && !DaoFactory.GetInvoiceTaxDao().IsExist(line.InvoiceTax1ID)) return false; if (line.InvoiceTax2ID > 0 && !DaoFactory.GetInvoiceTaxDao().IsExist(line.InvoiceTax2ID)) return false; } return true; } private List CreateInvoiceLines(List invoiceLines, Invoice invoice) { var result = new List(); for (var i = 0; i < invoiceLines.Count; i++) { var line = new InvoiceLine { ID = 0, InvoiceID = invoice.ID, InvoiceItemID = invoiceLines[i].InvoiceItemID, InvoiceTax1ID = invoiceLines[i].InvoiceTax1ID, InvoiceTax2ID = invoiceLines[i].InvoiceTax2ID, SortOrder = i, Description = invoiceLines[i].Description, Quantity = invoiceLines[i].Quantity, Price = invoiceLines[i].Price, Discount = Convert.ToInt32(invoiceLines[i].Discount) }; line.ID = DaoFactory.GetInvoiceLineDao().SaveOrUpdateInvoiceLine(line); result.Add(line); } return result; } /// /// Updates the selected invoice with the parameters (contactId, consigneeId, etc.) specified in the request /// /// Invoice ID /// Invoice issue date /// Invoice template type /// Invoice contact ID /// Invoice consignee ID /// Invoice entity ID /// Invoice billing address ID /// Invoice delivery address ID /// Invoice due date /// Invoice language /// Invoice currency /// Invoice exchange rate /// Invoice purchase order number /// Invoice terms /// Invoice description /// Invoice lines list /// Update invoice /// Invoices /// Invoice /// /// /// [Update(@"invoice/{id:int}")] public InvoiceDto UpdateInvoice( int id, CreateOrUpdateInvoiceInDto inDto) { ApiDateTime issueDate = inDto.IssueDate; int templateType = inDto.TemplateType; int contactId = inDto.ContactId; int consigneeId = inDto.ConsigneeId; int entityId = inDto.EntityId; int billingAddressID = inDto.BillingAddressID; int deliveryAddressID = inDto.DeliveryAddressID; ApiDateTime dueDate = inDto.DueDate; string language = inDto.Language; string currency = inDto.Currency; decimal exchangeRate = inDto.ExchangeRate; string purchaseOrderNumber = inDto.PurchaseOrderNumber; string terms = inDto.Terms; string description = inDto.Description; IEnumerable invoiceLines = inDto.InvoiceLines; var invoiceLinesList = invoiceLines != null ? invoiceLines.ToList() : new List(); if (!invoiceLinesList.Any() || !IsLinesForInvoiceCorrect(invoiceLinesList)) throw new ArgumentException(); var invoice = DaoFactory.GetInvoiceDao().GetByID(id); if (invoice == null || !CRMSecurity.CanEdit(invoice)) throw new ItemNotFoundException(); invoice.IssueDate = issueDate; invoice.TemplateType = (InvoiceTemplateType)templateType; invoice.ContactID = contactId; invoice.ConsigneeID = consigneeId; invoice.EntityType = EntityType.Opportunity; invoice.EntityID = entityId; invoice.DueDate = dueDate; invoice.Language = language; invoice.Currency = !String.IsNullOrEmpty(currency) ? currency.ToUpper() : null; ; invoice.ExchangeRate = exchangeRate; invoice.PurchaseOrderNumber = purchaseOrderNumber; invoice.Terms = terms; invoice.Description = description; invoice.JsonData = null; CRMSecurity.DemandCreateOrUpdate(invoice); if (billingAddressID > 0) { var address = DaoFactory.GetContactInfoDao().GetByID(billingAddressID); if (address == null || address.InfoType != ContactInfoType.Address || address.Category != (int)AddressCategory.Billing || address.ContactID != contactId) throw new ArgumentException(); } if (deliveryAddressID > 0) { var address = DaoFactory.GetContactInfoDao().GetByID(deliveryAddressID); if (address == null || address.InfoType != ContactInfoType.Address || address.Category != (int)AddressCategory.Postal || address.ContactID != consigneeId) throw new ArgumentException(); } DaoFactory.GetInvoiceDao().SaveOrUpdateInvoice(invoice); DaoFactory.GetInvoiceLineDao().DeleteInvoiceLines(invoice.ID); CreateInvoiceLines(invoiceLinesList, invoice); DaoFactory.GetInvoiceDao().UpdateInvoiceJsonData(invoice, billingAddressID, deliveryAddressID); if (Global.CanDownloadInvoices) { // PdfQueueWorker.StartTask(HttpContext.Current, TenantManager.GetCurrentTenant().TenantId, SecurityContext.CurrentAccount.ID, invoice.ID); } return InvoiceDtoHelper.Get(invoice); } /// /// Returns the pdf file associated with the invoice with the ID specified in the request /// /// Invoice ID /// Get invoice pdf file /// Invoices /// File [Read(@"invoice/{invoiceid:int}/pdf")] public FileWrapper GetInvoicePdfExistOrCreate(int invoiceid) { if (invoiceid <= 0) throw new ArgumentException(); var invoice = DaoFactory.GetInvoiceDao().GetByID(invoiceid); if (invoice == null) throw new ItemNotFoundException(); if (!CRMSecurity.CanAccessTo(invoice)) { throw CRMSecurity.CreateSecurityException(); } return FileWrapperHelper.Get(GetInvoicePdfExistingOrCreate(invoice)); } private ASC.Files.Core.File GetInvoicePdfExistingOrCreate(ASC.CRM.Core.Entities.Invoice invoice) { var existingFile = invoice.GetInvoiceFile(DaoFactory); if (existingFile != null) { return existingFile; } else { var newFile = PdfCreator.CreateFile(invoice, DaoFactory); invoice.FileID = Int32.Parse(newFile.ID.ToString()); DaoFactory.GetInvoiceDao().UpdateInvoiceFileID(invoice.ID, invoice.FileID); DaoFactory.GetRelationshipEventDao().AttachFiles(invoice.ContactID, invoice.EntityType, invoice.EntityID, new[] { invoice.FileID }); return newFile; } } /// /// Returns information about the generation of the pdf file of the invoice /// /// Invoice ID /// Storage Url /// Revision ID /// Check invoice pdf file /// Invoices /// ConverterData [Create(@"invoice/converter/data")] public ConverterData GetInvoiceConverterData(int invoiceId, string storageUrl, string revisionId) { if (invoiceId <= 0) throw new ArgumentException(); var invoice = DaoFactory.GetInvoiceDao().GetByID(invoiceId); if (invoice == null) throw new ItemNotFoundException(); if (!CRMSecurity.CanAccessTo(invoice)) { throw CRMSecurity.CreateSecurityException(); } var converterData = new ConverterData { StorageUrl = storageUrl, RevisionId = revisionId, InvoiceId = invoiceId }; var existingFile = invoice.GetInvoiceFile(DaoFactory); if (existingFile != null) { converterData.FileId = invoice.FileID; return converterData; } if (string.IsNullOrEmpty(storageUrl) || string.IsNullOrEmpty(revisionId)) { return PdfCreator.StartCreationFileAsync(invoice); } else { var convertedFile = PdfCreator.GetConvertedFile(converterData, DaoFactory); if (convertedFile != null) { invoice.FileID = Int32.Parse(convertedFile.ID.ToString()); DaoFactory.GetInvoiceDao().UpdateInvoiceFileID(invoice.ID, invoice.FileID); DaoFactory.GetRelationshipEventDao().AttachFiles(invoice.ContactID, invoice.EntityType, invoice.EntityID, new[] { invoice.FileID }); converterData.FileId = invoice.FileID; return converterData; } else { return converterData; } } } /// /// Returns the existence of the invoice with the Number specified in the request /// /// Invoice number /// Check invoice existence by number /// Invoices /// IsExist [Read(@"invoice/bynumber/exist")] public Boolean GetInvoiceByNumberExistence(string number) { if (String.IsNullOrEmpty(number)) throw new ArgumentException(); return DaoFactory.GetInvoiceDao().IsExist(number); } /// /// Returns the detailed information about the invoice with the Number specified in the request /// /// Invoice number /// Get invoice by number /// Invoices /// Invoice [Read(@"invoice/bynumber")] public InvoiceDto GetInvoiceByNumber(string number) { if (String.IsNullOrEmpty(number)) throw new ArgumentException(); var invoice = DaoFactory.GetInvoiceDao().GetByNumber(number); if (invoice == null) throw new ItemNotFoundException(); if (!CRMSecurity.CanAccessTo(invoice)) { throw CRMSecurity.CreateSecurityException(); } return InvoiceDtoHelper.Get(invoice); } /// /// Returns the list of invoice items matching the creteria specified in the request /// /// Status /// InventoryStock /// Get invoice item list /// Invoices /// InvoiceItem list [Read(@"invoiceitem/filter")] public IEnumerable GetInvoiceItems(int status, bool? inventoryStock) { IEnumerable result; InvoiceItemSortedByType sortBy; OrderBy invoiceOrderBy; var searchString = ApiContext.FilterValue; if (InvoiceItemSortedByType.TryParse(ApiContext.SortBy, true, out sortBy)) { invoiceOrderBy = new OrderBy(sortBy, !ApiContext.SortDescending); } else if (String.IsNullOrEmpty(ApiContext.SortBy)) { invoiceOrderBy = new OrderBy(InvoiceItemSortedByType.Name, true); } else { invoiceOrderBy = null; } var fromIndex = (int)ApiContext.StartIndex; var count = (int)ApiContext.Count; if (invoiceOrderBy != null) { result = DaoFactory.GetInvoiceItemDao().GetInvoiceItems( searchString, status, inventoryStock, fromIndex, count, invoiceOrderBy) .ConvertAll(x => InvoiceItemDtoHelper.Get(x)); ApiContext.SetDataPaginated(); ApiContext.SetDataFiltered(); ApiContext.SetDataSorted(); } else { result = DaoFactory.GetInvoiceItemDao().GetInvoiceItems( searchString, status, inventoryStock, 0, 0, null) .ConvertAll(x => InvoiceItemDtoHelper.Get(x)); } int totalCount; if (result.Count() < count) { totalCount = fromIndex + result.Count(); } else { totalCount = DaoFactory.GetInvoiceItemDao().GetInvoiceItemsCount( searchString, status, inventoryStock); } ApiContext.SetTotalCount(totalCount); return result; } /// /// Returns the detailed information about the invoice item with the ID specified in the request /// /// Invoice Item ID /// Get invoice item by ID /// Invoices /// Invoice Item [Read(@"invoiceitem/{invoiceitemid:int}")] public InvoiceItemDto GetInvoiceItemByID(int invoiceitemid) { if (invoiceitemid <= 0) throw new ArgumentException(); var invoiceItem = DaoFactory.GetInvoiceItemDao().GetByID(invoiceitemid); if (invoiceItem == null) throw new ItemNotFoundException(); return InvoiceItemDtoHelper.Get(invoiceItem); } /// /// Creates the invoice line with the parameters (invoiceId, invoiceItemId, etc.) specified in the request /// /// Invoice ID /// Invoice item ID /// First invoice tax ID /// Second invoice tax ID /// Sort Order /// Description /// Quantity /// Price /// Discount /// Create invoice line /// Invoices /// InvoiceLine [Create(@"invoiceline")] public InvoiceLineDto CreateInvoiceLine( CreateOrUpdateInvoiceLineInDto inDto ) { int invoiceId = inDto.InvoiceId; int invoiceItemId = inDto.InvoiceItemId; int invoiceTax1Id = inDto.InvoiceTax1Id; int invoiceTax2Id = inDto.InvoiceTax2Id; int sortOrder = inDto.SortOrder; string description = inDto.Description; int quantity = inDto.Quantity; decimal price = inDto.Price; int discount = inDto.Discount; var invoiceLine = new InvoiceLine { InvoiceID = invoiceId, InvoiceItemID = invoiceItemId, InvoiceTax1ID = invoiceTax1Id, InvoiceTax2ID = invoiceTax2Id, SortOrder = sortOrder, Description = description, Quantity = quantity, Price = price, Discount = discount }; if (invoiceId <= 0) throw new ArgumentException(); var invoice = DaoFactory.GetInvoiceDao().GetByID(invoiceId); CRMSecurity.DemandCreateOrUpdate(invoiceLine, invoice); invoiceLine.ID = DaoFactory.GetInvoiceLineDao().SaveOrUpdateInvoiceLine(invoiceLine); DaoFactory.GetInvoiceDao().UpdateInvoiceJsonDataAfterLinesUpdated(invoice); if (Global.CanDownloadInvoices) { // PdfQueueWorker.StartTask(HttpContext.Current, TenantManager.GetCurrentTenant().TenantId, SecurityContext.CurrentAccount.ID, invoice.ID); } return InvoiceLineDtoHelper.Get(invoiceLine); } /// /// Updates the selected invoice line with the parameters (invoiceId, invoiceItemId, etc.) specified in the request /// /// Line ID /// Invoice ID /// Invoice item ID /// First invoice tax ID /// Second invoice tax ID /// Sort Order /// Description /// Quantity /// Price /// Discount /// Update invoice line /// Invoices /// InvoiceLine [Update(@"invoiceline/{id:int}")] public InvoiceLineDto UpdateInvoiceLine( int id, CreateOrUpdateInvoiceLineInDto inDto ) { int invoiceId = inDto.InvoiceId; int invoiceItemId = inDto.InvoiceItemId; int invoiceTax1Id = inDto.InvoiceTax1Id; int invoiceTax2Id = inDto.InvoiceTax2Id; int sortOrder = inDto.SortOrder; string description = inDto.Description; int quantity = inDto.Quantity; decimal price = inDto.Price; int discount = inDto.Discount; if (invoiceId <= 0) throw new ArgumentException(); var invoiceLine = DaoFactory.GetInvoiceLineDao().GetByID(id); if (invoiceLine == null || invoiceLine.InvoiceID != invoiceId) throw new ItemNotFoundException(); invoiceLine.InvoiceID = invoiceId; invoiceLine.InvoiceItemID = invoiceItemId; invoiceLine.InvoiceTax1ID = invoiceTax1Id; invoiceLine.InvoiceTax2ID = invoiceTax2Id; invoiceLine.SortOrder = sortOrder; invoiceLine.Description = description; invoiceLine.Quantity = quantity; invoiceLine.Price = price; invoiceLine.Discount = discount; var invoice = DaoFactory.GetInvoiceDao().GetByID(invoiceId); CRMSecurity.DemandCreateOrUpdate(invoiceLine, invoice); DaoFactory.GetInvoiceLineDao().SaveOrUpdateInvoiceLine(invoiceLine); DaoFactory.GetInvoiceDao().UpdateInvoiceJsonDataAfterLinesUpdated(invoice); if (Global.CanDownloadInvoices) { // PdfQueueWorker.StartTask(HttpContext.Current, TenantManager.GetCurrentTenant().TenantId, SecurityContext.CurrentAccount.ID, invoice.ID); } return InvoiceLineDtoHelper.Get(invoiceLine); } /// /// Deletes the invoice line with the ID specified in the request /// /// Line ID /// Delete invoice line /// Invoices /// Line ID [Delete(@"invoiceline/{id:int}")] public int DeleteInvoiceLine(int id) { var invoiceLine = DaoFactory.GetInvoiceLineDao().GetByID(id); if (invoiceLine == null) throw new ItemNotFoundException(); if (!DaoFactory.GetInvoiceLineDao().CanDelete(invoiceLine.ID)) throw new Exception("Can't delete invoice line"); var invoice = DaoFactory.GetInvoiceDao().GetByID(invoiceLine.InvoiceID); if (invoice == null) throw new ItemNotFoundException(); if (!CRMSecurity.CanEdit(invoice)) throw CRMSecurity.CreateSecurityException(); DaoFactory.GetInvoiceLineDao().DeleteInvoiceLine(id); DaoFactory.GetInvoiceDao().UpdateInvoiceJsonDataAfterLinesUpdated(invoice); if (Global.CanDownloadInvoices) { // PdfQueueWorker.StartTask(HttpContext.Current, TenantManager.GetCurrentTenant().TenantId, SecurityContext.CurrentAccount.ID, invoice.ID); } return id; } /// /// Creates the invoice item with the parameters (title, description, price, etc.) specified in the request /// /// Item title /// Item description /// Item price /// Item stock keeping unit /// Item quantity /// Item stock quantity /// Track inventory /// Item first invoice tax ID /// Item second invoice tax ID /// Create invoice item /// Invoices /// InvoiceItem [Create(@"invoiceitem")] public InvoiceItemDto CreateInvoiceItem( CreateOrUpdateInvoiceItemInDto inDto ) { string title = inDto.Title; string description = inDto.Description; decimal price = inDto.Price; string sku = inDto.Sku; int quantity = inDto.Quantity; int stockQuantity = inDto.StockQuantity; bool trackInventory = inDto.TrackInventory; int invoiceTax1id = inDto.InvoiceTax1id; int invoiceTax2id = inDto.InvoiceTax2id; if (!CRMSecurity.IsAdmin) { throw CRMSecurity.CreateSecurityException(); } if (String.IsNullOrEmpty(title) || price <= 0) throw new ArgumentException(); var invoiceItem = new InvoiceItem { Title = title, Description = description, Price = price, StockKeepingUnit = sku, StockQuantity = stockQuantity, TrackInventory = trackInventory, InvoiceTax1ID = invoiceTax1id, InvoiceTax2ID = invoiceTax2id }; invoiceItem = DaoFactory.GetInvoiceItemDao().SaveOrUpdateInvoiceItem(invoiceItem); MessageService.Send(MessageAction.InvoiceItemCreated, MessageTarget.Create(invoiceItem.ID), invoiceItem.Title); return InvoiceItemDtoHelper.Get(invoiceItem); } /// /// Updates the selected invoice item with the parameters (title, description, price, etc.) specified in the request /// /// Item ID /// Item title /// Item description /// Item price /// Item stock keeping unit /// Item quantity /// Item stock quantity /// Track inventory /// Item first invoice tax ID /// Item second invoice tax ID /// Update invoice item /// Invoices /// InvoiceItem [Update(@"invoiceitem/{id:int}")] public InvoiceItemDto UpdateInvoiceItem(int id, CreateOrUpdateInvoiceItemInDto inDto ) { string title = inDto.Title; string description = inDto.Description; decimal price = inDto.Price; string sku = inDto.Sku; int quantity = inDto.Quantity; int stockQuantity = inDto.StockQuantity; bool trackInventory = inDto.TrackInventory; int invoiceTax1id = inDto.InvoiceTax1id; int invoiceTax2id = inDto.InvoiceTax2id; if (!CRMSecurity.IsAdmin) { throw CRMSecurity.CreateSecurityException(); } if (id <= 0 || String.IsNullOrEmpty(title) || price <= 0) throw new ArgumentException(); if (!DaoFactory.GetInvoiceItemDao().IsExist(id)) throw new ItemNotFoundException(); var invoiceItem = new InvoiceItem { ID = id, Title = title, Description = description, Price = price, StockKeepingUnit = sku, StockQuantity = stockQuantity, TrackInventory = trackInventory, InvoiceTax1ID = invoiceTax1id, InvoiceTax2ID = invoiceTax2id }; invoiceItem = DaoFactory.GetInvoiceItemDao().SaveOrUpdateInvoiceItem(invoiceItem); MessageService.Send(MessageAction.InvoiceItemUpdated, MessageTarget.Create(invoiceItem.ID), invoiceItem.Title); return InvoiceItemDtoHelper.Get(invoiceItem); } /// /// Deletes the invoice item with the ID specified in the request /// /// Item ID /// Delete invoice item /// Invoices /// InvoiceItem [Delete(@"invoiceitem/{id:int}")] public InvoiceItemDto DeleteInvoiceItem(int id) { if (!CRMSecurity.IsAdmin) { throw CRMSecurity.CreateSecurityException(); } if (id <= 0) throw new ArgumentException(); var invoiceItem = DaoFactory.GetInvoiceItemDao().DeleteInvoiceItem(id); if (invoiceItem == null) throw new ItemNotFoundException(); MessageService.Send(MessageAction.InvoiceItemDeleted, MessageTarget.Create(invoiceItem.ID), invoiceItem.Title); return InvoiceItemDtoHelper.Get(invoiceItem); } /// /// Deletes the group of invoice items with the IDs specified in the request /// /// Item ID list /// Delete Invoice item group /// Invoices /// InvoiceItem list [Delete(@"invoiceitem")] public IEnumerable DeleteBatchItems(IEnumerable ids) { if (!CRMSecurity.IsAdmin) { throw CRMSecurity.CreateSecurityException(); } if (ids == null) throw new ArgumentException(); ids = ids.Distinct(); var items = DaoFactory.GetInvoiceItemDao().DeleteBatchInvoiceItems(ids.ToArray()); MessageService.Send(MessageAction.InvoiceItemsDeleted, MessageTarget.Create(ids), items.Select(x => x.Title)); return items.ConvertAll(x => InvoiceItemDtoHelper.Get(x)); } /// /// Returns the list of invoice taxes /// /// Get invoice taxes list /// Invoices /// InvoiceTax list [Read(@"invoice/tax")] public IEnumerable GetInvoiceTaxes() { return DaoFactory.GetInvoiceTaxDao().GetAll().ConvertAll(x => InvoiceTaxDtoHelper.Get(x)); } /// /// Creates the invoice tax with the parameters (name, description, rate) specified in the request /// /// Tax name /// Tax description /// Tax rate /// Create invoice tax /// Invoices /// InvoiceTax [Create(@"invoice/tax")] public InvoiceTaxDto CreateInvoiceTax( [FromBody] CreateOrUpdateInvoiceTax inDto) { string name = inDto.Name; string description = inDto.Description; decimal rate = inDto.Rate; if (!CRMSecurity.IsAdmin) { throw CRMSecurity.CreateSecurityException(); } if (String.IsNullOrEmpty(name)) throw new ArgumentException(CRMInvoiceResource.EmptyTaxNameError); if (DaoFactory.GetInvoiceTaxDao().IsExist(name)) throw new ArgumentException(CRMInvoiceResource.ExistTaxNameError); var invoiceTax = new InvoiceTax { Name = name, Description = description, Rate = rate }; invoiceTax = DaoFactory.GetInvoiceTaxDao().SaveOrUpdateInvoiceTax(invoiceTax); MessageService.Send(MessageAction.InvoiceTaxCreated, MessageTarget.Create(invoiceTax.ID), invoiceTax.Name); return InvoiceTaxDtoHelper.Get(invoiceTax); } /// /// Updates the selected invoice tax with the parameters (name, description, rate) specified in the request /// /// Tax ID /// Tax name /// Tax description /// Tax rate /// Update invoice tax /// Invoices /// InvoiceTax [Update(@"invoice/tax/{id:int}")] public InvoiceTaxDto UpdateInvoiceTax( int id, CreateOrUpdateInvoiceTax inDto) { string name = inDto.Name; string description = inDto.Description; decimal rate = inDto.Rate; if (!CRMSecurity.IsAdmin) { throw CRMSecurity.CreateSecurityException(); } if (id <= 0 || String.IsNullOrEmpty(name)) throw new ArgumentException(CRMInvoiceResource.EmptyTaxNameError); if (!DaoFactory.GetInvoiceTaxDao().IsExist(id)) throw new ItemNotFoundException(); var invoiceTax = new InvoiceTax { ID = id, Name = name, Description = description, Rate = rate }; invoiceTax = DaoFactory.GetInvoiceTaxDao().SaveOrUpdateInvoiceTax(invoiceTax); MessageService.Send(MessageAction.InvoiceTaxUpdated, MessageTarget.Create(invoiceTax.ID), invoiceTax.Name); return InvoiceTaxDtoHelper.Get(invoiceTax); } /// /// Delete the invoice tax with the ID specified in the request /// /// Tax ID /// Delete invoice tax /// Invoices /// InvoiceTax [Delete(@"invoice/tax/{id:int}")] public InvoiceTaxDto DeleteInvoiceTax(int id) { if (!CRMSecurity.IsAdmin) { throw CRMSecurity.CreateSecurityException(); } if (id <= 0) throw new ArgumentException(); var invoiceTax = DaoFactory.GetInvoiceTaxDao().DeleteInvoiceTax(id); if (invoiceTax == null) throw new ItemNotFoundException(); MessageService.Send(MessageAction.InvoiceTaxDeleted, MessageTarget.Create(invoiceTax.ID), invoiceTax.Name); return InvoiceTaxDtoHelper.Get(invoiceTax); } /// /// Get default invoice settings /// /// Get default invoice settings /// Invoices /// InvoiceSetting [Read(@"invoice/settings")] public InvoiceSetting GetSettings() { return DaoFactory.GetInvoiceDao().GetSettings(); } /// /// Save default invoice number /// /// Is autogenerated /// Prefix /// Number /// Save default invoice number /// Invoices /// InvoiceSetting [Update(@"invoice/settings/name")] public InvoiceSetting SaveNumberSettings( SaveNumberSettingsInDto inDto ) { var autogenerated = inDto.AutoGenerated; var number = inDto.Number; var prefix = inDto.Prefix; if (!CRMSecurity.IsAdmin) throw CRMSecurity.CreateSecurityException(); if (autogenerated && string.IsNullOrEmpty(number)) throw new ArgumentException(); if (autogenerated && DaoFactory.GetInvoiceDao().IsExist(prefix + number)) throw new ArgumentException(); var invoiceSetting = GetSettings(); invoiceSetting.Autogenerated = autogenerated; invoiceSetting.Prefix = prefix; invoiceSetting.Number = number; var settings = DaoFactory.GetInvoiceDao().SaveInvoiceSettings(invoiceSetting); MessageService.Send(MessageAction.InvoiceNumberFormatUpdated); return settings; } /// /// Save default invoice terms /// /// Terms /// Save default invoice terms /// Invoices /// InvoiceSetting [Update(@"invoice/settings/terms")] public InvoiceSetting SaveTermsSettings(string terms) { if (!CRMSecurity.IsAdmin) throw CRMSecurity.CreateSecurityException(); var invoiceSetting = GetSettings(); invoiceSetting.Terms = terms; var result = DaoFactory.GetInvoiceDao().SaveInvoiceSettings(invoiceSetting); MessageService.Send(MessageAction.InvoiceDefaultTermsUpdated); return result; } /// false [Update(@"invoice/{invoiceid:int}/creationdate")] public void SetInvoiceCreationDate(int invoiceid, ApiDateTime creationDate) { var dao = DaoFactory.GetInvoiceDao(); var invoice = dao.GetByID(invoiceid); if (invoice == null || !CRMSecurity.CanAccessTo(invoice)) throw new ItemNotFoundException(); dao.SetInvoiceCreationDate(invoiceid, creationDate); } /// false [Update(@"invoice/{invoiceid:int}/lastmodifeddate")] public void SetInvoiceLastModifedDate(int invoiceid, ApiDateTime lastModifedDate) { var dao = DaoFactory.GetInvoiceDao(); var invoice = dao.GetByID(invoiceid); if (invoice == null || !CRMSecurity.CanAccessTo(invoice)) throw new ItemNotFoundException(); dao.SetInvoiceLastModifedDate(invoiceid, lastModifedDate); } private IEnumerable ToListInvoiceBaseDtos(ICollection items) { if (items == null || items.Count == 0) return new List(); var result = new List(); var contactIDs = items.Select(item => item.ContactID); contactIDs.ToList().AddRange(items.Select(item => item.ConsigneeID)); var contacts = DaoFactory.GetContactDao().GetContacts(contactIDs.Distinct().ToArray()) .ToDictionary(item => item.ID, x => ContactDtoHelper.GetContactBaseWithEmailDto(x)); foreach (var invoice in items) { var invoiceDto = InvoiceBaseDtoHelper.Get(invoice); if (contacts.ContainsKey(invoice.ContactID)) { invoiceDto.Contact = contacts[invoice.ContactID]; } if (contacts.ContainsKey(invoice.ConsigneeID)) { invoiceDto.Consignee = contacts[invoice.ContactID]; } if (invoice.EntityID > 0) { invoiceDto.Entity = ToEntityDto(invoice.EntityType, invoice.EntityID); //Need to optimize } invoiceDto.Cost = invoice.GetInvoiceCost(DaoFactory); result.Add(invoiceDto); } return result; } private EntityDto ToEntityDto(EntityType entityType, int entityID) { if (entityID == 0) return null; var result = new EntityDto { EntityId = entityID }; switch (entityType) { case EntityType.Case: var caseObj = DaoFactory.GetCasesDao().GetByID(entityID); if (caseObj == null) return null; result.EntityType = "case"; result.EntityTitle = caseObj.Title; break; case EntityType.Opportunity: var dealObj = DaoFactory.GetDealDao().GetByID(entityID); if (dealObj == null) return null; result.EntityType = "opportunity"; result.EntityTitle = dealObj.Title; break; default: return null; } return result; } } }