} // End of the GetInvoices method /// <summary> /// Get an invoice to export /// </summary> public async Task<AnnytabDoxTradeRoot> GetInvoice(string id) { // Get data Dictionary<string, string> labels = await GetLabels(); CompanySettingsRoot company = await GetCompanySettings(); // Make sure that company and company.Settings not is null if (company == null || company.CompanySettings == null) { this.logger.LogError($"GetInvoice: {id}, Could not find any company settings."); return null; } // Get the invoice FortnoxResponse<InvoiceRoot> fr = await this.nox_client.Get<InvoiceRoot>($"invoices/{id}"); // Return if model or model.Invoice is null if (fr.model == null || fr.model.Invoice == null) { // Log the error and return null this.logger.LogError(fr.error); return null; } // Check if the invoice should be exported bool export_invoice = false; foreach (Label label in fr.model.Invoice.Labels) { if (labels.ContainsKey(label.Id) && labels[label.Id] == "a-dox-trade-v1") { // Export the invoice export_invoice = true; break; } } // Return null if the invoice not should be exported if (export_invoice == false) { return null; } // Get the customer FortnoxResponse<CustomerRoot> fr_customer = await this.nox_client.Get<CustomerRoot>($"customers/{fr.model.Invoice.CustomerNumber}"); // Return if model or model.Customer is null if (fr_customer.model == null || fr_customer.model.Customer == null) { // Log the error and return null this.logger.LogError(fr_customer.error); return null; } // Create an invoice AnnytabDoxTrade post = await CreateInvoice(company, fr.model, fr_customer.model); // Return the post return new AnnytabDoxTradeRoot { document_type = post.document_type, document = post, email = fr_customer.model.Customer.Email, language_code = fr.model.Invoice.Language }; } // End of the GetInvoice method
/// <summary> /// Create a new fortnox exporter /// </summary> public FortnoxExporter(ILogger<IFortnoxExporter> logger, IFortnoxClient nox_client, IOptions<DefaultValues> default_values) { // Set values for instance variables this.logger = logger; this.nox_client = nox_client; this.default_values = default_values.Value; this._company_settings = null; this._labels = null; } // End of the constructor
} // End of the AddFreight method /// <summary> /// Get a party with company information /// </summary> private PartyInformation GetCompanyParty(CompanySettingsRoot company, string reference) { // Return the party return new PartyInformation() { person_id = company.CompanySettings.OrganizationNumber, person_name = company.CompanySettings.Name, address_line_1 = company.CompanySettings.Address, postcode = company.CompanySettings.ZipCode, city_name = company.CompanySettings.City, country_name = company.CompanySettings.Country, country_code = company.CompanySettings.CountryCode, contact_name = reference, phone_number = company.CompanySettings.Phone1, email = company.CompanySettings.Email, vat_number = company.CompanySettings.VATNumber }; } // End of the GetCompanyParty method
} // End of the GetCompanyParty method /// <summary> /// Get payment options /// </summary> private IList<PaymentOption> GetPaymentOptions(CompanySettingsRoot company) { // Create the list to return IList<PaymentOption> payment_options = new List<PaymentOption>(); // Add payment options if (string.IsNullOrEmpty(company.CompanySettings.IBAN) == false) { payment_options.Add(new PaymentOption { name = "IBAN", account_reference = company.CompanySettings.IBAN, bank_identifier_code = company.CompanySettings.BIC }); } if (string.IsNullOrEmpty(company.CompanySettings.BG) == false) { payment_options.Add(new PaymentOption { name = "BG", account_reference = company.CompanySettings.BG, bank_identifier_code = "BGABSESS", bank_name = "Bankgirocentralen BGC AB", bank_country_code = "SE" }); } if (string.IsNullOrEmpty(company.CompanySettings.PG) == false) { payment_options.Add(new PaymentOption { name = "PG", account_reference = company.CompanySettings.PG, bank_identifier_code = "NDEASESS", bank_name = "Nordea Bank AB", bank_country_code = "SE" }); } // Return the list return payment_options; } // End of the GetPaymentOptions method
} // End of the GetLabels method /// <summary> /// Get company settings /// </summary> public async Task<CompanySettingsRoot> GetCompanySettings() { // Return company settings if they already exists if(this._company_settings != null) { return this._company_settings; } // Get company settings FortnoxResponse<CompanySettingsRoot> fr = await this.nox_client.Get<CompanySettingsRoot>("settings/company"); // Log errors if (string.IsNullOrEmpty(fr.error) == false) { this.logger.LogError(fr.error); } // Create a reference to company settings this._company_settings = fr.model; // Return company settings return this._company_settings; } // End of the GetCompanySettings 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
} // End of the CreateOrderConfirmation method /// <summary> /// Create a purchase order /// </summary> private AnnytabDoxTrade CreatePurchaseOrder(CompanySettingsRoot company, OrderRoot root, SupplierRoot supplier_root, IList<ProductRow> product_rows, decimal? total_weight) { // Calculate totals decimal? net_sum = 0; decimal? vat_sum = 0; foreach (ProductRow row in product_rows) { net_sum += row.unit_price * row.quantity; vat_sum += row.unit_price * row.quantity * row.vat_rate; } // Create a Annytab Dox Trade document AnnytabDoxTrade post = new AnnytabDoxTrade(); post.id = root.Order.DocumentNumber; post.document_type = "order"; post.issue_date = DateTime.Now.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture); post.delivery_date = root.Order.DeliveryDate; post.seller_references = new Dictionary<string, string>(); post.seller_references.Add("supplier_id", supplier_root.Supplier.SupplierNumber); post.buyer_references = new Dictionary<string, string>(); post.buyer_references.Add("customer_id", supplier_root.Supplier.OurCustomerNumber); post.terms_of_delivery = root.Order.TermsOfDelivery; post.terms_of_payment = supplier_root.Supplier.TermsOfPayment; post.mode_of_delivery = root.Order.WayOfDelivery; post.total_weight_kg = total_weight; post.currency_code = supplier_root.Supplier.Currency; post.comment = root.Order.Remarks; post.seller_information = new PartyInformation { person_id = supplier_root.Supplier.OrganisationNumber, person_name = supplier_root.Supplier.Name, address_line_1 = supplier_root.Supplier.Address1, address_line_2 = supplier_root.Supplier.Address2, postcode = supplier_root.Supplier.ZipCode, city_name = supplier_root.Supplier.City, country_name = supplier_root.Supplier.Country, country_code = supplier_root.Supplier.CountryCode, contact_name = supplier_root.Supplier.YourReference, phone_number = supplier_root.Supplier.Phone1, email = supplier_root.Supplier.Email, vat_number = supplier_root.Supplier.VATNumber }; post.buyer_information = GetCompanyParty(company, supplier_root.Supplier.OurReference); post.delivery_information = new PartyInformation { person_name = root.Order.DeliveryName, address_line_1 = root.Order.DeliveryAddress1, address_line_2 = root.Order.DeliveryAddress2, postcode = root.Order.DeliveryZipCode, city_name = root.Order.DeliveryCity, country_name = root.Order.DeliveryCountry }; post.product_rows = product_rows; post.subtotal = net_sum; post.vat_total = vat_sum; post.rounding = 0M; post.total = net_sum + vat_sum; // Return the post return post; } // End of the CreatePurchaseOrder method
} // End of the GetOrders method /// <summary> /// Get an order to export /// </summary> public async Task<IList<AnnytabDoxTradeRoot>> GetOrder(string id) { // Get data Dictionary<string, string> labels = await GetLabels(); CompanySettingsRoot company = await GetCompanySettings(); // Make sure that company and company.Settings not is null if (company == null || company.CompanySettings == null) { this.logger.LogError($"GetOrder: {id}, Could not find any company settings."); return null; } // Get the order FortnoxResponse<OrderRoot> fr = await this.nox_client.Get<OrderRoot>($"orders/{id}"); // Return if model or model.Order is null if (fr.model == null || fr.model.Order == null) { // Log the error and return null this.logger.LogError(fr.error); return null; } // Check if the order should be exported bool export_order = false; bool export_purchase_orders = false; foreach (Label label in fr.model.Order.Labels) { if (labels.ContainsKey(label.Id) && labels[label.Id] == "a-dox-trade-v1") { // Export the order export_order = true; } else if (labels.ContainsKey(label.Id) && labels[label.Id] == "a-dox-trade-v1-po") { // Export the purchase order export_purchase_orders = true; } } // Return null if nothing should be exported if (export_order == false && export_purchase_orders == false) { return null; } // Get the customer FortnoxResponse<CustomerRoot> fr_customer = await this.nox_client.Get<CustomerRoot>($"customers/{fr.model.Order.CustomerNumber}"); // Return if model or model.Customer is null if (fr_customer.model == null || fr_customer.model.Customer == null) { // Log the error and return null this.logger.LogError(fr_customer.error); return null; } // Create the list to return IList<AnnytabDoxTradeRoot> posts = new List<AnnytabDoxTradeRoot>(); // Create an order confirmation if(export_order == true) { AnnytabDoxTrade post = await CreateOrderConfirmation(company, fr.model, fr_customer.model); posts.Add(new AnnytabDoxTradeRoot { document_type = post.document_type, document = post, email = fr_customer.model.Customer.Email, language_code = fr.model.Order.Language }); } // Create purchase orders if(export_purchase_orders == true) { // Create variables IDictionary<string, SupplierRoot> suppliers = new Dictionary<string, SupplierRoot>(); IDictionary<string, IList<ProductRow>> supplier_rows = new Dictionary<string, IList<ProductRow>>(); decimal? total_weight = 0M; // Get suppliers foreach (OrderRow row in fr.model.Order.OrderRows) { // Get the article FortnoxResponse<ArticleRoot> fr_article = await this.nox_client.Get<ArticleRoot>($"articles/{row.ArticleNumber}"); // Make sure that the article was found if (fr_article.model != null && fr_article.model.Article != null) { // Get the supplier if(string.IsNullOrEmpty(fr_article.model.Article.SupplierNumber) == false) { // Check if the supplier exists if (suppliers.ContainsKey(fr_article.model.Article.SupplierNumber) == false) { // Get the supplier FortnoxResponse<SupplierRoot> fr_supplier = await this.nox_client.Get<SupplierRoot>($"suppliers/{fr_article.model.Article.SupplierNumber}"); // Add the supplier if(fr_supplier != null && fr_supplier.model != null) { // Add the supplier suppliers.Add(fr_article.model.Article.SupplierNumber, fr_supplier.model); } else { this.logger.LogError(fr_supplier.error); } } // Check if the supplier has order rows if(supplier_rows.ContainsKey(fr_article.model.Article.SupplierNumber) == false && suppliers.ContainsKey(fr_article.model.Article.SupplierNumber) == true) { // Add the row supplier_rows.Add(fr_article.model.Article.SupplierNumber, new List<ProductRow>()); } // Add to the total weight total_weight += fr_article.model.Article.Weight != null ? (fr_article.model.Article.Weight * row.OrderedQuantity) / 1000M : 0; // Add the row supplier_rows[fr_article.model.Article.SupplierNumber].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 = fr_article.model.Article.Description, vat_rate = row.VAT / 100, quantity = row.OrderedQuantity, unit_code = row.Unit, unit_price = fr_article.model.Article.PurchasePrice, // 0M subrows = null }); } } else { // Log the error this.logger.LogError(fr_article.error); } } // Create a purchase order to each supplier foreach(KeyValuePair<string, SupplierRoot> entry in suppliers) { // Create a purchase order AnnytabDoxTrade post = CreatePurchaseOrder(company, fr.model, entry.Value, supplier_rows[entry.Key], total_weight); // Add the document posts.Add(new AnnytabDoxTradeRoot { document_type = "purchase_order_" + entry.Value.Supplier.SupplierNumber, document = post, email = entry.Value.Supplier.Email, language_code = "en" }); } } // Return the list with posts return posts; } // End of the GetOrder method