} // End of the AddOrderRows method /// <summary> /// Add supplier invoice rows recursively /// </summary> private async Task AddSupplierInvoiceRows(IList<ProductRow> product_rows, IList<SupplierInvoiceRow> supplier_invoice_rows) { // Loop product rows foreach (ProductRow row in product_rows) { // Unit if (string.IsNullOrEmpty(row.unit_code) == false) { row.unit_code = CommonTools.ConvertToAlphanumeric(row.unit_code).ToLower(); await AddUnit(row.unit_code); } // Article, add if there is an identifier ArticleRoot article_root = null; if (string.IsNullOrEmpty(row.product_code) == false || string.IsNullOrEmpty(row.manufacturer_code) == false || string.IsNullOrEmpty(row.gtin) == false) { article_root = await AddArticle(row); } // Add a supplier invoice row supplier_invoice_rows.Add(new SupplierInvoiceRow { ArticleNumber = article_root != null ? article_root.Article.ArticleNumber : null, Account = article_root == null ? this.default_values.PurchaseAccount : null, ItemDescription = row.product_name, Quantity = row.quantity, Price = row.unit_price //Unit = article_root != null ? article_root.Article.Unit : row.unit_code }); // Check if there is sub rows if (row.subrows != null && row.subrows.Count > 0) { await AddSupplierInvoiceRows(row.subrows, supplier_invoice_rows); } } } // End of the AddSupplierInvoiceRows method
} // End of the AddOfferRows method /// <summary> /// Add order rows recursively /// </summary> private async Task AddOrderRows(IList<ProductRow> product_rows, IList<OrderRow> order_rows) { // Loop product rows foreach (ProductRow row in product_rows) { // Unit if (string.IsNullOrEmpty(row.unit_code) == false) { row.unit_code = CommonTools.ConvertToAlphanumeric(row.unit_code).ToLower(); await AddUnit(row.unit_code); } // Article, add if there is an identifier ArticleRoot article_root = null; if (string.IsNullOrEmpty(row.product_code) == false || string.IsNullOrEmpty(row.manufacturer_code) == false || string.IsNullOrEmpty(row.gtin) == false) { article_root = await AddArticle(row); } // Add a order row order_rows.Add(new OrderRow { ArticleNumber = article_root != null ? article_root.Article.ArticleNumber : null, Description = row.product_name, OrderedQuantity = row.quantity, DeliveredQuantity = row.quantity, Price = row.unit_price, Unit = article_root != null ? article_root.Article.Unit : row.unit_code }); // Check if there is sub rows if (row.subrows != null && row.subrows.Count > 0) { await AddOrderRows(row.subrows, order_rows); } } } // End of the AddOrderRows method
} // End of the AddOrder method /// <summary> /// Add an supplier invoice /// </summary> public async Task<SupplierInvoiceRoot> AddSupplierInvoice(string dox_email, AnnytabDoxTrade doc) { // Terms of payment if (string.IsNullOrEmpty(doc.terms_of_payment) == false) { doc.terms_of_payment = CommonTools.ConvertToAlphanumeric(doc.terms_of_payment).ToUpper().Replace("-", ""); await AddTermsOfPayment(doc.terms_of_payment); } // Currency if (string.IsNullOrEmpty(doc.currency_code) == false) { doc.currency_code = doc.currency_code.ToUpper(); await AddCurrency(doc.currency_code); } // Upsert the supplier SupplierRoot supplier_root = await UpsertSupplier(dox_email, doc); // Return if the supplier_root is null if(supplier_root == null || supplier_root.Supplier == null) { return null; } // Create a list with supplier invoice rows IList<SupplierInvoiceRow> rows = new List<SupplierInvoiceRow>(); //// Add accounts payable amount //if(doc.total != null && doc.total != 0M) //{ // rows.Add(new SupplierInvoiceRow // { // Code = "TOT", // Total = doc.total * -1 // }); //} //// Add value added tax //if (doc.vat_total != null && doc.vat_total != 0M) //{ // rows.Add(new SupplierInvoiceRow // { // Code = "VAT", // Total = doc.vat_total // }); //} //// Add rounding //if(doc.rounding != null && doc.rounding != 0M) //{ // rows.Add(new SupplierInvoiceRow // { // Code = "ROV", // Total = doc.rounding // }); //} // Add supplier invoice rows if (doc.product_rows != null) { await AddSupplierInvoiceRows(doc.product_rows, rows); } // Create a supplier invoice SupplierInvoiceRoot root = new SupplierInvoiceRoot { SupplierInvoice = new SupplierInvoice { SupplierNumber = supplier_root.Supplier.SupplierNumber, InvoiceNumber = string.IsNullOrEmpty(doc.payment_reference) == false ? doc.payment_reference : null, InvoiceDate = string.IsNullOrEmpty(doc.issue_date) == false ? doc.issue_date : null, DueDate = string.IsNullOrEmpty(doc.due_date) == false ? doc.due_date : null, Currency = doc.currency_code, Comments = doc.comment, Total = doc.total != null ? doc.total : 0M, VAT = doc.vat_total != null ? doc.vat_total : 0M, RoundOffValue = doc.rounding != null ? doc.rounding : 0M, SupplierInvoiceRows = rows } }; // Add a supplier invoice FortnoxResponse<SupplierInvoiceRoot> fr = await this.nox_client.Add<SupplierInvoiceRoot>(root, "supplierinvoices"); // Log errors if (string.IsNullOrEmpty(fr.error) == false) { this.logger.LogError(fr.error); } // Return the supplier invoice return fr.model; } // End of the AddSupplierInvoice method
} // End of the AddOffer method /// <summary> /// Add an order /// </summary> public async Task<OrderRoot> AddOrder(string dox_email, AnnytabDoxTrade doc) { // Terms of delivery if (string.IsNullOrEmpty(doc.terms_of_delivery) == false) { doc.terms_of_delivery = CommonTools.ConvertToAlphanumeric(doc.terms_of_delivery).ToUpper(); await AddTermsOfDelivery(doc.terms_of_delivery); } // Terms of payment if (string.IsNullOrEmpty(doc.terms_of_payment) == false) { doc.terms_of_payment = CommonTools.ConvertToAlphanumeric(doc.terms_of_payment).ToUpper().Replace("-", ""); await AddTermsOfPayment(doc.terms_of_payment); } // Way of delivery if (string.IsNullOrEmpty(doc.mode_of_delivery) == false) { doc.mode_of_delivery = CommonTools.ConvertToAlphanumeric(doc.mode_of_delivery).ToUpper(); await AddWayOfDelivery(doc.mode_of_delivery); } // Currency if (string.IsNullOrEmpty(doc.currency_code) == false) { doc.currency_code = doc.currency_code.ToUpper(); await AddCurrency(doc.currency_code); } // Upsert the customer CustomerRoot customer_root = await UpsertCustomer(dox_email, doc); // Return if the customer is null if (customer_root == null || customer_root.Customer == null) { return null; } // Create a list with order rows IList<OrderRow> rows = new List<OrderRow>(); // Add order rows if (doc.product_rows != null) { await AddOrderRows(doc.product_rows, rows); } // Create an order OrderRoot root = new OrderRoot { Order = new Order { CustomerNumber = customer_root.Customer.CustomerNumber, OrderDate = string.IsNullOrEmpty(doc.issue_date) == false ? doc.issue_date : null, DeliveryDate = string.IsNullOrEmpty(doc.delivery_date) == false ? doc.delivery_date : null, YourOrderNumber = doc.buyer_references != null && doc.buyer_references.ContainsKey("order_id") ? doc.buyer_references["order_id"] : null, ExternalInvoiceReference1 = string.IsNullOrEmpty(doc.payment_reference) == false ? doc.payment_reference : null, ExternalInvoiceReference2 = string.IsNullOrEmpty(doc.id) == false ? doc.id : null, Comments = doc.comment, OrderRows = rows, Currency = doc.currency_code, VATIncluded = false } }; // Add the order FortnoxResponse<OrderRoot> fr = await this.nox_client.Add<OrderRoot>(root, "orders"); // Log errors if (string.IsNullOrEmpty(fr.error) == false) { this.logger.LogError(fr.error); } // Return the order return fr.model; } // End of the AddOrder method
} // End of the AddArticle method /// <summary> /// Add or update a customer /// </summary> public async Task<CustomerRoot> UpsertCustomer(string dox_email, AnnytabDoxTrade doc) { // Create variables FortnoxResponse<CustomerRoot> fr = new FortnoxResponse<CustomerRoot>(); bool customer_exists = false; string customer_email = doc.buyer_information != null && string.IsNullOrEmpty(doc.buyer_information.email) == false ? doc.buyer_information.email : dox_email; // Find customers on email FortnoxResponse<CustomersRoot> fr_page = await this.nox_client.Get<CustomersRoot>($"customers?email={customer_email}"); // Log errors if (string.IsNullOrEmpty(fr_page.error) == false) { this.logger.LogError(fr_page.error); } // Make sure that at least one customer was found if (fr_page.model != null && fr_page.model.Customers != null && fr_page.model.Customers.Count > 0) { // Get a customer fr = await this.nox_client.Get<CustomerRoot>($"customers/{fr_page.model.Customers[0].CustomerNumber}"); // Log errors if (string.IsNullOrEmpty(fr.error) == false) { this.logger.LogError(fr.error); } } // Check if the customer exists if (fr.model != null) { customer_exists = true; } else { fr.model = new CustomerRoot { Customer = new Customer() }; } // Update the customer: ONLY SET VAT TYPE, ACCOUNT IS SET IN ARTICLE fr.model.Customer.Email = customer_email; if (doc.seller_information != null) { fr.model.Customer.OurReference = string.IsNullOrEmpty(fr.model.Customer.OurReference) == true ? doc.seller_information.contact_name : fr.model.Customer.OurReference; } if(doc.buyer_information != null) { fr.model.Customer.Name = string.IsNullOrEmpty(doc.buyer_information.person_name) == false ? doc.buyer_information.person_name : fr.model.Customer.Name; fr.model.Customer.OrganisationNumber = string.IsNullOrEmpty(doc.buyer_information.person_id) == false ? doc.buyer_information.person_id : fr.model.Customer.OrganisationNumber; fr.model.Customer.VATNumber = string.IsNullOrEmpty(doc.buyer_information.vat_number) == false ? doc.buyer_information.vat_number : fr.model.Customer.VATNumber; fr.model.Customer.YourReference = string.IsNullOrEmpty(doc.buyer_information.contact_name) == false ? doc.buyer_information.contact_name : fr.model.Customer.YourReference; fr.model.Customer.Phone1 = string.IsNullOrEmpty(doc.buyer_information.phone_number) == false ? doc.buyer_information.phone_number : fr.model.Customer.Phone1; fr.model.Customer.Address1 = string.IsNullOrEmpty(doc.buyer_information.address_line_1) == false ? doc.buyer_information.address_line_1 : fr.model.Customer.Address1; fr.model.Customer.Address2 = string.IsNullOrEmpty(doc.buyer_information.address_line_2) == false ? doc.buyer_information.address_line_2 : fr.model.Customer.Address2; fr.model.Customer.ZipCode = string.IsNullOrEmpty(doc.buyer_information.postcode) == false ? doc.buyer_information.postcode : fr.model.Customer.ZipCode; fr.model.Customer.City = string.IsNullOrEmpty(doc.buyer_information.city_name) == false ? doc.buyer_information.city_name : fr.model.Customer.City; fr.model.Customer.CountryCode = string.IsNullOrEmpty(doc.buyer_information.country_code) == false ? doc.buyer_information.country_code : fr.model.Customer.CountryCode; fr.model.Customer.EmailOffer = string.IsNullOrEmpty(fr.model.Customer.EmailOffer) == true ? customer_email : fr.model.Customer.EmailOffer; fr.model.Customer.EmailOrder = string.IsNullOrEmpty(fr.model.Customer.EmailOrder) == true ? customer_email : fr.model.Customer.EmailOrder; fr.model.Customer.EmailInvoice = string.IsNullOrEmpty(fr.model.Customer.EmailInvoice) == true ? customer_email : fr.model.Customer.EmailInvoice; } if(doc.delivery_information != null) { fr.model.Customer.DeliveryName = string.IsNullOrEmpty(doc.delivery_information.person_name) == false ? doc.delivery_information.person_name : fr.model.Customer.DeliveryName; fr.model.Customer.DeliveryPhone1 = string.IsNullOrEmpty(doc.delivery_information.phone_number) == false ? doc.delivery_information.phone_number : fr.model.Customer.DeliveryPhone1; fr.model.Customer.DeliveryAddress1 = string.IsNullOrEmpty(doc.delivery_information.address_line_1) == false ? doc.delivery_information.address_line_1 : fr.model.Customer.DeliveryAddress1; fr.model.Customer.DeliveryAddress2 = string.IsNullOrEmpty(doc.delivery_information.address_line_2) == false ? doc.delivery_information.address_line_2 : fr.model.Customer.DeliveryAddress2; fr.model.Customer.DeliveryCity = string.IsNullOrEmpty(doc.delivery_information.city_name) == false ? doc.delivery_information.city_name : fr.model.Customer.DeliveryCity; fr.model.Customer.DeliveryCountryCode = string.IsNullOrEmpty(doc.delivery_information.country_code) == false ? doc.delivery_information.country_code : fr.model.Customer.DeliveryCountryCode; fr.model.Customer.DeliveryZipCode = string.IsNullOrEmpty(doc.delivery_information.postcode) == false ? doc.delivery_information.postcode : fr.model.Customer.DeliveryZipCode; } fr.model.Customer.Currency = string.IsNullOrEmpty(doc.currency_code) == false ? doc.currency_code : fr.model.Customer.Currency; fr.model.Customer.TermsOfDelivery = string.IsNullOrEmpty(doc.terms_of_delivery) == false ? doc.terms_of_delivery : fr.model.Customer.TermsOfDelivery; fr.model.Customer.TermsOfPayment = string.IsNullOrEmpty(doc.terms_of_payment) == false ? doc.terms_of_payment : fr.model.Customer.TermsOfPayment; fr.model.Customer.VATType = CommonTools.GetCustomerVatType(fr.model.Customer, this.default_values); fr.model.Customer.WayOfDelivery = string.IsNullOrEmpty(doc.mode_of_delivery) == false ? doc.mode_of_delivery : fr.model.Customer.WayOfDelivery; fr.model.Customer.Type = string.IsNullOrEmpty(fr.model.Customer.Type) == true && string.IsNullOrEmpty(fr.model.Customer.VATNumber) == false ? "COMPANY" : fr.model.Customer.Type; fr.model.Customer.PriceList = string.IsNullOrEmpty(fr.model.Customer.PriceList) == true ? this.default_values.PriceList : fr.model.Customer.PriceList; // Add or update the customer if (customer_exists == true) { fr = await this.nox_client.Update<CustomerRoot>(fr.model, $"customers/{fr.model.Customer.CustomerNumber}"); } else { fr = await this.nox_client.Add<CustomerRoot>(fr.model, "customers"); } // Log errors if (string.IsNullOrEmpty(fr.error) == false) { this.logger.LogError(fr.error); } // Return the post return fr.model; } // End of the UpsertCustomer method
} // End of the AddAccount method /// <summary> /// Add an article if it does not exist /// </summary> public async Task<ArticleRoot> AddArticle(ProductRow row) { // Create a reference to an article root FortnoxResponse<ArticleRoot> fr = new FortnoxResponse<ArticleRoot>(); // Make sure that the product code only consists of alphanumeric characters row.product_code = string.IsNullOrEmpty(row.product_code) == false ? CommonTools.ConvertToAlphanumeric(row.product_code) : null; // Find the article if (string.IsNullOrEmpty(row.gtin) == false) { // Try to get articles on EAN FortnoxResponse<ArticlesRoot> fr_page = await this.nox_client.Get<ArticlesRoot>($"articles?ean={row.gtin}"); // Log errors if (string.IsNullOrEmpty(fr_page.error) == false) { this.logger.LogError(fr_page.error); } // Make sure that at least one article was found if (fr_page.model != null && fr_page.model.Articles != null && fr_page.model.Articles.Count > 0) { // Get an article fr = await this.nox_client.Get<ArticleRoot>($"articles/{fr_page.model.Articles[0].ArticleNumber}"); // Log errors if (string.IsNullOrEmpty(fr.error) == false) { this.logger.LogError(fr.error); } } } if(fr.model == null && string.IsNullOrEmpty(row.manufacturer_code) == false) { // Try to get articles on manufacturer code FortnoxResponse<ArticlesRoot> fr_page = await this.nox_client.Get<ArticlesRoot>($"articles?manufacturerarticlenumber={row.manufacturer_code}"); // Log errors if (string.IsNullOrEmpty(fr_page.error) == false) { this.logger.LogError(fr_page.error); } // Make sure that at least one article was found if (fr_page.model != null && fr_page.model.Articles != null && fr_page.model.Articles.Count > 0) { // Get an article fr = await this.nox_client.Get<ArticleRoot>($"articles/{fr_page.model.Articles[0].ArticleNumber}"); // Log errors if (string.IsNullOrEmpty(fr.error) == false) { this.logger.LogError(fr.error); } } } if(fr.model == null && string.IsNullOrEmpty(row.product_code) == false) { // Get an article fr = await this.nox_client.Get<ArticleRoot>($"articles/{row.product_code}"); // Log errors if (string.IsNullOrEmpty(fr.error) == false) { this.logger.LogError(fr.error); } } // Add the article if it does not exist if (fr.model == null) { // Create a new article fr.model = new ArticleRoot { Article = new Article { ArticleNumber = string.IsNullOrEmpty(row.product_code) == false ? row.product_code : null, ConstructionAccount = this.default_values.SalesAccountSEREVERSEDVAT, Description = row.product_name, EAN = string.IsNullOrEmpty(row.gtin) == false ? row.gtin : null, EUAccount = this.default_values.SalesAccountEUREVERSEDVAT, EUVATAccount = this.default_values.SalesAccountEUVAT, ExportAccount = this.default_values.SalesAccountEXPORT, ManufacturerArticleNumber = string.IsNullOrEmpty(row.manufacturer_code) == false ? row.manufacturer_code : null, PurchaseAccount = this.default_values.PurchaseAccount, SalesAccount = CommonTools.GetArticleSalesAccount(row.vat_rate, this.default_values), Unit = string.IsNullOrEmpty(row.unit_code) == false ? row.unit_code : null } }; // Add an article fr = await this.nox_client.Add<ArticleRoot>(fr.model, "articles"); // Log errors if (string.IsNullOrEmpty(fr.error) == false) { this.logger.LogError(fr.error); } // Add a default price if (fr.model != null) { PriceRoot price = new PriceRoot { Price = new Price { ArticleNumber = fr.model.Article.ArticleNumber, PriceList = this.default_values.PriceList, FromQuantity = 0, Amount = row.unit_price } }; // Add a price FortnoxResponse<PriceRoot> fr_price = await this.nox_client.Add<PriceRoot>(price, "prices"); // Log errors if (string.IsNullOrEmpty(fr_price.error) == false) { this.logger.LogError(fr_price.error); } } } // Return the post return fr.model; } // End of the AddArticle method
} // End of the run method /// <summary> /// Import to Fortnox /// </summary> private async Task RunImport(string directory, IDoxservrFilesClient dox_files_client, IFortnoxClient nox_client) { // Log the start this.logger.LogInformation("START: Importing documents to Fortnox!"); // Get files from doxservr await GetDoxservrFiles(directory); // Create a list with accounts IList<string> accounts = new List<string> { this.default_values.SalesAccountEUREVERSEDVAT, this.default_values.SalesAccountEUVAT, this.default_values.SalesAccountEXPORT, this.default_values.SalesAccountSE0, this.default_values.SalesAccountSE12, this.default_values.SalesAccountSE25, this.default_values.SalesAccountSE6, this.default_values.SalesAccountSEREVERSEDVAT, this.default_values.PurchaseAccount }; // Add accounts foreach(string account in accounts) { if(string.IsNullOrEmpty(account) == false) { await this.fortnox_importer.AddAccount(account); } } // Add a price list if (string.IsNullOrEmpty(this.default_values.PriceList) == false) { this.default_values.PriceList = this.default_values.PriceList.ToUpper(); await this.fortnox_importer.AddPriceList(this.default_values.PriceList); } // Upsert currency rates //DoxservrResponse<FixerRates> dr_fixer_rates = await this.fixer_client.UpdateCurrencyRates(directory); //if(dr_fixer_rates.model != null) //{ // await this.fortnox_importer.UpsertCurrencies(dr_fixer_rates.model); //} // Get email senders EmailSendersRoot email_senders = null; if(this.default_values.OnlyAllowTrustedSenders == true) { email_senders = await this.fortnox_importer.GetTrustedEmailSenders(); } // Get downloaded metadata files string[] metadata_files = System.IO.Directory.GetFiles(directory + "\\Files\\Meta\\"); // Loop metadata files foreach(string meta_path in metadata_files) { // Metadata FileDocument post = null; try { // Get the meta data string meta_data = System.IO.File.ReadAllText(meta_path, Encoding.UTF8); // Make sure that there is meta data if (string.IsNullOrEmpty(meta_data) == true) { this.logger.LogError($"File is empty: {meta_path}"); continue; } // Get the post post = JsonConvert.DeserializeObject<FileDocument>(meta_data); } catch (Exception ex) { // Log the error this.logger.LogError(ex, $"Deserialize file: {meta_path}", null); continue; } // Make sure that the post not is null if(post == null) { // Log the error this.logger.LogError($"Post is null: {meta_path}", null); continue; } // Get the sender Party sender = null; foreach (Party party in post.parties) { if (party.is_sender == 1) { sender = party; break; } } // Check if we only should allow trusted senders if(this.default_values.OnlyAllowTrustedSenders == true) { // Check if the sender is a trusted sender bool trusted = false; foreach(EmailSender email_sender in email_senders.EmailSenders.TrustedSenders) { if(email_sender.Email == sender.email) { trusted = true; break; } } // Check if the sender is trusted if(trusted == false) { // Log the error this.logger.LogError($"{sender.email} is not trusted, add the email to the list of trusted email addresses in Fortnox (Inställningar/Arkivplats)."); continue; } } // Get the file path string file_path = directory + "\\Files\\" + post.id + CommonTools.GetExtensions(post.filename); // Make sure that the file exists if(System.IO.File.Exists(file_path) == false) { // Log the error this.logger.LogError($"File not found: {file_path}."); continue; } // Document AnnytabDoxTrade doc = null; try { // Get file data string file_data = System.IO.File.ReadAllText(file_path, CommonTools.GetEncoding(post.file_encoding, Encoding.UTF8)); // Make sure that there is file data if(string.IsNullOrEmpty(file_data) == true) { // Log the error this.logger.LogError($"File is empty: {file_path}."); continue; } // Get the document doc = JsonConvert.DeserializeObject<AnnytabDoxTrade>(file_data); } catch(Exception ex) { // Log the error this.logger.LogError(ex, $"Deserialize file: {file_path}", null); continue; } // Make sure that the document not is null if (doc == null) { // Log the error this.logger.LogError($"Post is null: {file_path}", null); continue; } // Create an error variable bool error = false; // Check the document type if (doc.document_type == "request_for_quotation") { // Log information this.logger.LogInformation($"Starts to import offer {post.id}.json to Fortnox."); // Import as offer OfferRoot offer_root = await this.fortnox_importer.AddOffer(sender.email, doc); if (offer_root == null) { // Log the error error = true; this.logger.LogError($"Offer, {post.id}.json was not imported to Fortnox."); } else { // Log information this.logger.LogInformation($"Offer, {post.id}.json was imported to Fortnox."); } } else if (doc.document_type == "quotation") { // Log information this.logger.LogInformation($"Quotation {post.id}.json is not imported to Fortnox."); } else if (doc.document_type == "order") { // Log information this.logger.LogInformation($"Starts to import order {post.id}.json to Fortnox."); // Import as order OrderRoot order_root = await this.fortnox_importer.AddOrder(sender.email, doc); if (order_root == null) { // Log the error error = true; this.logger.LogError($"Order, {post.id}.json was not imported to Fortnox."); } else { // Log information this.logger.LogInformation($"Order, {post.id}.json was imported to Fortnox."); } } else if (doc.document_type == "order_confirmation") { // Log information this.logger.LogInformation($"Order confirmation {post.id}.json is not imported to Fortnox."); } else if (doc.document_type == "invoice") { // Log information this.logger.LogInformation($"Starts to import supplier invoice {post.id}.json to Fortnox."); // Import as supplier invoice SupplierInvoiceRoot invoice_root = await this.fortnox_importer.AddSupplierInvoice(sender.email, doc); if (invoice_root == null) { // Log the error error = true; this.logger.LogError($"Supplier invoice, {post.id}.json was not imported to Fortnox."); } else { // Log information this.logger.LogInformation($"Supplier invoice, {post.id}.json was imported to Fortnox."); } } else if (doc.document_type == "credit_invoice") { // Log information this.logger.LogInformation($"Starts to import supplier credit invoice {post.id}.json to Fortnox."); // Import as supplier credit invoice SupplierInvoiceRoot invoice_root = await this.fortnox_importer.AddSupplierInvoice(sender.email, doc); if (invoice_root == null) { // Log the error error = true; this.logger.LogError($"Supplier credit invoice, {post.id}.json was not imported to Fortnox."); } else { // Log information this.logger.LogInformation($"Supplier credit invoice, {post.id}.json was imported to Fortnox."); } } // Move files if no error was encountered if(error == false) { // Create destination paths string meta_destination = directory + $"\\Files\\Meta\\Imported\\{post.id}.json"; string file_destination = directory + $"\\Files\\Imported\\{post.id}.json"; try { // Delete destination files if the exists if(System.IO.File.Exists(meta_destination) == true) { System.IO.File.Delete(meta_destination); } if(System.IO.File.Exists(file_destination) == true) { System.IO.File.Delete(file_destination); } // Move files System.IO.Directory.Move(meta_path, meta_destination); System.IO.Directory.Move(file_path, file_destination); } catch (Exception ex) { // Log the exception this.logger.LogError(ex, "Moving files", null); } } } // Log the end this.logger.LogInformation("END: Importing documents to Fortnox!"); } // End of the RunImport method
} // End of the RunExport method #endregion #region Helper methods /// <summary> /// Get doxservr files /// </summary> /// <returns></returns> private async Task GetDoxservrFiles(string directory) { // Get new documents from doxservr DoxservrResponse<FileDocuments> dr = await this.dox_files_client.GetPage("", 0, -1, 0, 10); // Make sure that the model not is null if (dr.model == null) { // Log the error this.logger.LogError(dr.error); // Return from the method return; } // Loop as long as there is more posts to get while (true) { // Loop documents foreach (FileDocument fd in dr.model.items) { // Make sure that the file follows a standard if (string.Equals(fd.standard_name, "Annytab Dox Trade v1", StringComparison.OrdinalIgnoreCase) == false) { continue; } // File stream FileStream file_stream = null; try { // Create a file stream file_stream = System.IO.File.OpenWrite(directory + "\\Files\\" + fd.id + CommonTools.GetExtensions(fd.filename)); // Get the file DoxservrResponse<bool> file_response = await this.dox_files_client.GetFile(fd.id, file_stream); // Get the file if (file_response.model == false) { // Continue with the loop, the file was not downloaded continue; } // Save metadata to disk System.IO.File.WriteAllText(directory + "\\Files\\Meta\\" + fd.id + ".json", JsonConvert.SerializeObject(fd)); } catch (Exception ex) { // Log the error this.logger.LogError(ex, $"Save files to disk: {fd.id}", null); continue; } finally { // Dispose of the stream if (file_stream != null) { file_stream.Dispose(); } } } // Check if there is more files if (string.IsNullOrEmpty(dr.model.ct) == false) { // Get the next page dr = await this.dox_files_client.GetPage(dr.model.ct, 0, -1, 0, 10); // Make sure that the model not is null if(dr.model == null) { // Log the error this.logger.LogError(dr.error); // Break out from the loop break; } } else { // Break out from the loop break; } } } // End of the GetDoxservrFiles method
} // End of the CreatePurchaseOrder method /// <summary> /// Create a invoice /// </summary> private async Task<AnnytabDoxTrade> CreateInvoice(CompanySettingsRoot company, InvoiceRoot root, CustomerRoot customer_root) { // Create a Annytab Dox Trade document AnnytabDoxTrade post = new AnnytabDoxTrade(); post.id = root.Invoice.DocumentNumber; post.document_type = root.Invoice.Credit == true ? "credit_invoice" : "invoice"; post.payment_reference = string.IsNullOrEmpty(root.Invoice.OCR) == false ? root.Invoice.OCR : root.Invoice.DocumentNumber; post.issue_date = root.Invoice.InvoiceDate; post.due_date = root.Invoice.DueDate; post.delivery_date = root.Invoice.DeliveryDate; post.seller_references = new Dictionary<string, string>(); post.seller_references.Add("quotation_id", root.Invoice.OfferReference); post.seller_references.Add("order_id", root.Invoice.OrderReference); post.seller_references.Add("invoice_id", root.Invoice.InvoiceReference); post.buyer_references = new Dictionary<string, string>(); post.buyer_references.Add("customer_id", root.Invoice.CustomerNumber); post.buyer_references.Add("order_id", root.Invoice.YourOrderNumber); post.terms_of_delivery = root.Invoice.TermsOfDelivery; post.terms_of_payment = root.Invoice.TermsOfPayment; post.mode_of_delivery = root.Invoice.WayOfDelivery; post.total_weight_kg = 0M; post.penalty_interest = this.default_values.PenaltyInterest; post.currency_code = root.Invoice.Currency; post.vat_country_code = company.CompanySettings.CountryCode; post.comment = root.Invoice.Remarks; post.seller_information = GetCompanyParty(company, root.Invoice.OurReference); post.buyer_information = new PartyInformation { person_id = root.Invoice.OrganisationNumber, person_name = root.Invoice.CustomerName, address_line_1 = root.Invoice.Address1, address_line_2 = root.Invoice.Address2, postcode = root.Invoice.ZipCode, city_name = root.Invoice.City, country_name = root.Invoice.Country, contact_name = root.Invoice.YourReference, phone_number = root.Invoice.Phone1, email = customer_root.Customer.Email }; post.delivery_information = new PartyInformation { person_name = root.Invoice.DeliveryName, address_line_1 = root.Invoice.DeliveryAddress1, address_line_2 = root.Invoice.DeliveryAddress2, postcode = root.Invoice.DeliveryZipCode, city_name = root.Invoice.DeliveryCity, country_name = root.Invoice.DeliveryCountry }; post.payment_options = GetPaymentOptions(company); post.product_rows = new List<ProductRow>(); foreach (InvoiceRow row in root.Invoice.InvoiceRows) { // Get the article FortnoxResponse<ArticleRoot> fr_article = await this.nox_client.Get<ArticleRoot>($"articles/{row.ArticleNumber}"); // Make sure that article root and article not is null if (fr_article.model == null || fr_article.model.Article == null) { fr_article.model = new ArticleRoot { Article = new Article() }; } // Add to the total weight post.total_weight_kg += fr_article.model.Article.Weight != null ? (fr_article.model.Article.Weight * row.DeliveredQuantity) / 1000M : 0; // Calculate the price decimal? price = root.Invoice.VATIncluded == true ? row.Price / ((100 + row.VAT) / 100) : row.Price; if (row.Discount > 0M && row.DiscountType == "AMOUNT") { if (root.Invoice.VATIncluded == true) { decimal? discount = row.Discount / ((100 + row.VAT) / 100); price = price - (discount / row.DeliveredQuantity); } else { price = price - (row.Discount / row.DeliveredQuantity); } } else if (row.Discount > 0M && row.DiscountType == "PERCENT") { price = price - (price * (row.Discount / 100)); } // Add a product row post.product_rows.Add(new ProductRow { product_code = fr_article.model.Article.ArticleNumber, manufacturer_code = fr_article.model.Article.ManufacturerArticleNumber, gtin = fr_article.model.Article.EAN, product_name = row.Description, vat_rate = row.VAT / 100, quantity = row.DeliveredQuantity, unit_code = row.Unit, unit_price = price, subrows = null }); } decimal? invoice_fee = AddInvoiceFee(root.Invoice.VATIncluded, root.Invoice.AdministrationFee, root.Invoice.AdministrationFeeVAT, post.product_rows, root.Invoice.Language); decimal? freight_fee = AddFreight(root.Invoice.VATIncluded, root.Invoice.Freight, root.Invoice.FreightVAT, post.product_rows, root.Invoice.Language); post.vat_specification = CommonTools.GetVatSpecification(post.product_rows); post.subtotal = root.Invoice.Net + invoice_fee + freight_fee; post.vat_total = root.Invoice.TotalVAT; post.rounding = root.Invoice.RoundOff; post.total = root.Invoice.Total; post.paid_amount = root.Invoice.TotalToPay - root.Invoice.Balance; post.balance_due = root.Invoice.Balance; // Return the post return post; } // End of the CreateInvoice method