using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Baza_Reklam.Classes.Helpers;
using Baza_Reklam.Classes.Interfaces;
using Baza_Reklam.Classes.Model;
using Baza_Reklam.Classes.Model.Enums;
using Baza_Reklam.Classes.Repositories;

namespace Baza_Reklam
{
    public partial class ZamowieniaForm : Form
    {
        private CustomerRepository customerRepository;
        private List<IProduct> productsWithOrder = new List<IProduct>();
        private List<IProduct> productsWithoutOrder = new List<IProduct>();
        private AgentRepository agentRepository;

        private REKLAMADataSet.KLIENCIRow klient;
        private List<Title> _titles;

        private int idZamowienia;

        private REKLAMADataSetTableAdapters.KLIENCITableAdapter klienciTableAdapter =
            new REKLAMADataSetTableAdapters.KLIENCITableAdapter();

        private SLOWNIKDataSetTableAdapters.AGENCJETableAdapter agencjeTableAdapter =
            new SLOWNIKDataSetTableAdapters.AGENCJETableAdapter();

        private SLOWNIKDataSetTableAdapters.AGENCITableAdapter agenciTableAdapter =
            new SLOWNIKDataSetTableAdapters.AGENCITableAdapter();

        private REKLAMADataSetTableAdapters.UKAZE_SIE_W_NRTableAdapter emisjeTableAdapter =
            new REKLAMADataSetTableAdapters.UKAZE_SIE_W_NRTableAdapter();

        private REKLAMADataSetTableAdapters.FAKTURA_DETAILSTableAdapter fakturyDetailsTableAdapter =
            new REKLAMADataSetTableAdapters.FAKTURA_DETAILSTableAdapter();

        private REKLAMADataSetTableAdapters.WplatyTableAdapter wplatyTableAdapter =
            new REKLAMADataSetTableAdapters.WplatyTableAdapter();

        private REKLAMADataSetTableAdapters.DatyWydanTableAdapter datyWydanTableAdapter =
            new REKLAMADataSetTableAdapters.DatyWydanTableAdapter();

        private SLOWNIKDataSetTableAdapters.Kursy_WalutTableAdapter kursyWalutTableAdapter =
            new SLOWNIKDataSetTableAdapters.Kursy_WalutTableAdapter();


        public ZamowieniaForm(REKLAMADataSet.KLIENCIRow klient)
        {
            InitializeComponent();
            InitTableAdatpers(klient.CustomerID);

            this.klient = klient;
        }

        public ZamowieniaForm(int idKlienta)
        {
            InitializeComponent();
            InitTableAdatpers(idKlienta);

            klient = klienciTableAdapter.GetDataByCustomerId(idKlienta)[0];
        }

        public ZamowieniaForm(int idKlienta, int idZamowienia)
        {
            InitializeComponent();
            InitTableAdatpers(idKlienta);

            klient = klienciTableAdapter.GetDataByCustomerId(idKlienta)[0];
            this.idZamowienia = idZamowienia;
        }

        private void InitTableAdatpers(int customerId)
        {
            customerRepository = new CustomerRepository(ConnString.getConnString().Value);
            agentRepository = new AgentRepository(ConnString.getConnString().Value);

            productsWithOrder = customerRepository.FindProductsWithOrders(customerId);
            productsWithoutOrder = customerRepository.FindProductsWithoutOrders(customerId);

            zamowieniaTableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;
            rEKLAMATableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;
            fAKTURYTableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;
            fakturyDetailsTableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;
            klienciTableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;
            agencjeTableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;
            agenciTableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;
            emisjeTableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;
            datyWydanTableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;
            kursyWalutTableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;
            wplatyTableAdapter.Connection.ConnectionString = ConnString.getConnString().Value;

            TitleRepository repository = new TitleRepository(ConnString.getConnString().Value);
            _titles = repository.FindAllActive();
        }

        private void BindProductsWithoutOrders()
        {
            rEKLAMADataGridView1.AutoGenerateColumns = false;
            rEKLAMADataGridView1.DataSource = null;
            rEKLAMADataGridView1.DataSource = productsWithoutOrder;
        }

        private void BindProductsWithOrders(int orderId)
        {
            rEKLAMADataGridView.AutoGenerateColumns = false;
            rEKLAMADataGridView.DataSource = null;
            rEKLAMADataGridView.DataSource = productsWithOrder.FindAll(delegate(IProduct p) { return p.OrderId == orderId; });
        }

        private void ZamowieniaForm_Load(object sender, EventArgs e)
        {
            BindProductsWithoutOrders();

            usunFaktureButton.Enabled = User.Instance().IsKierownik;
            dtpZmianaDaty.Enabled = User.Instance().IsKierownik;
            dtpZmianaDaty.Value = DateTime.Today;
            dtpZmianaDaty.MaxDate = DateTime.Today;

            zamowieniaBindingSource.CurrentChanged += zamowieniaBindingSource_CurrentChanged;

            zamowieniaTableAdapter.FillByIdKlienta(rEKLAMADataSet.zamowienia, klient.CustomerID);

            if (idZamowienia != 0)
            {
                zamowieniaBindingSource.Position = zamowieniaBindingSource.Find("idZamowienia", idZamowienia);

                BindProductsWithOrders(idZamowienia);

                fAKTURYTableAdapter.FillByIdZamowienia(rEKLAMADataSet.FAKTURY, idZamowienia);
            }
            else
                zamowieniaBindingSource.Position = 0;

            if (klient == null) return;

            KlientLabel.Text = klient.IskodKlientaNull()
                                   ? "BRAK KODU KLIENTA"
                                   : "KOD KLIENTA:  " + klient.kodKlienta;
        }

        private void dodajButton_Click(object sender, EventArgs e)
        {
            if (klient.IskodKlientaNull() || klient.kodKlienta.Trim() == string.Empty)
            {
                MessageBox.Show("Uzupełnij kod klienta");
                return;
            }

            AddZamowienieForm azf = new AddZamowienieForm(0, klient.CustomerID);
            if (azf.ShowDialog() == DialogResult.OK)
            {
                rEKLAMADataSet.zamowienia.ImportRow(azf.Zamowienia[0]);
                int idZam = azf.Zamowienia[0].idZamowienia;
                zamowieniaBindingSource.Position = zamowieniaBindingSource.Find("idZamowienia", idZam);
                rEKLAMATableAdapter.FillByIdZamowienia(rEKLAMADataSet.REKLAMA, idZam);
                fAKTURYTableAdapter.FillByIdZamowienia(rEKLAMADataSet.FAKTURY, idZam);
            }
        }

        private void edytujButton_Click(object sender, EventArgs e)
        {
            if (zamowieniaBindingSource.Current != null)
            {
                DataRowView z = (DataRowView)zamowieniaBindingSource.Current;
                REKLAMADataSet.zamowieniaRow zamowienie = (REKLAMADataSet.zamowieniaRow)z.Row;

                int idZam = zamowienie.idZamowienia;

                AddZamowienieForm azf = new AddZamowienieForm(idZam, klient.CustomerID);
                if (azf.ShowDialog() == DialogResult.OK)
                {
                    rEKLAMADataSet.zamowienia.Clear();
                    zamowieniaTableAdapter.FillByIdKlienta(rEKLAMADataSet.zamowienia, klient.CustomerID);
                    zamowieniaBindingSource.Position = zamowieniaBindingSource.Find("idZamowienia", idZam);
                }
            }
        }

        private void dodajDoZamButton_Click(object sender, EventArgs e)
        {
            if (zamowieniaBindingSource.Current == null || rEKLAMADataGridView1.SelectedRows.Count <= 0) return;

            DataRowView z = (DataRowView)zamowieniaBindingSource.Current;
            REKLAMADataSet.zamowieniaRow zamowienie = (REKLAMADataSet.zamowieniaRow)z.Row;

            IProduct product = (IProduct)rEKLAMADataGridView1.SelectedRows[0].DataBoundItem;

            string s = string.Empty;

            List<IProduct> productsInOrder = (List<IProduct>)rEKLAMADataGridView.DataSource;

            //if (!CanAddProductToOrder(product, productsWithOrder, zamowienie, out s))
            if (!CanAddProductToOrder(product, productsInOrder, zamowienie, out s))
            {
                MessageBox.Show(s, "Baza Reklam - Zamówienia i faktury", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            UpdateOrderAccount(product, zamowienie);

            product.OrderId = zamowienie.idZamowienia;
            customerRepository.AddProductToOrder(product);

            productsWithoutOrder.Remove(product);
            productsWithOrder.Add(product);

            if (s != string.Empty)
            {
                s += "\nReklamy nie mogą być w obrębie jednego zamówienia";
                MessageBox.Show(s, "Baza Reklam - dodawanie produktu do zamówienia", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            BindProductsWithOrders(zamowienie.idZamowienia);
            BindProductsWithoutOrders();
        }

        private void UpdateOrderAccount(IProduct product, REKLAMADataSet.zamowieniaRow order)
        {
            if (product.ProductType != ProductType.Advertisment || !order.IsidKontaNull()) return;

            // zmiana domyślnego konta do faktury dla EUR
            if (User.Instance().IdAgencji != 4 && product.Currency == "EUR")
            {
                if (User.Instance().IdAgencji == 1223940396 || User.Instance().IdAgencji == 1223940398)
                    order.idKonta = 3;
                else
                    order.idKonta = 5;

                zamowieniaTableAdapter.Update(rEKLAMADataSet.zamowienia);
            }
        }

        // private bool CanAddProductToOrder(IProduct product, List<IProduct> products, REKLAMADataSet.zamowieniaRow order, out string errorMessage)
        private bool CanAddProductToOrder(IProduct product, List<IProduct> productsInOrder, REKLAMADataSet.zamowieniaRow order, out string errorMessage)
        {
            StringBuilder sb = new StringBuilder();
            bool canAddProduct = true;

            if (order.zafakturowanoWszystko || order.zafakturowano)
            {
                sb.AppendLine("Zamówienie jest już zafakturowane.");
                canAddProduct = false;
            }

            if (productsInOrder.FindAll(delegate(IProduct p) { return p.Currency != product.Currency && p.OrderId == order.idZamowienia; }).Count > 0)
            {
                sb.AppendLine("Produkt jest w innej walucie niż pozostałe produkty w zamówieniu.");
                canAddProduct = false;
            }

            if (productsInOrder.FindAll(delegate(IProduct p) { return p.Vat != product.Vat && p.OrderId == order.idZamowienia; }).Count > 0)
            {
                sb.AppendLine("Produkt ma inną stawkę VAT niż pozostałe produkty w zamówieniu.");
                canAddProduct = false;
            }

            if (canAddProduct && product.ProductType == ProductType.Advertisment)
            {
                if (datyWydanTableAdapter.GetDataByPierwszaEmisjaWReklamie(product.Id).Rows.Count <= 0)
                {
                    sb.AppendLine("Reklama nie ma wybranych emisji.");
                    canAddProduct = false;
                }
            }

            if (canAddProduct && productsInOrder.Count > 0)
            {
                Title title1 = _titles.Find(delegate(Title title) { return title.Id == product.TitleId; });
                Title title2 = _titles.Find(delegate(Title title) { return title.Id == productsInOrder[0].TitleId; });
                if (title1 == null || title2 == null)
                {
                    sb.AppendLine("Nie określone tytuły produktów.");
                    canAddProduct = false;
                }
                else if (title1.InvoiceProvider != title2.InvoiceProvider)
                {
                    sb.AppendLine("Produkty mają różnych sprzedawców.\nNa fakturze może występować tylko jeden sprzedawca.");
                    canAddProduct = false;
                }
            }

            errorMessage = sb.ToString();
            return canAddProduct;
        }

        private void usunZZamButton_Click(object sender, EventArgs e)
        {
            if (zamowieniaBindingSource.Current == null || rEKLAMADataGridView.SelectedRows.Count == 0) return;

            IProduct product = (IProduct)rEKLAMADataGridView.SelectedRows[0].DataBoundItem;

            if (product.HasInvoice)
            {
                MessageBox.Show("Wybrany produkt posiada już zafakturowane elementy. Nie można go usunąć.",
                                "Baza Reklam - Zamówienia i faktury");
                return;
            }

            customerRepository.RemoveProductFromOrder(product);

            productsWithOrder.Remove(product);
            int orderId = product.OrderId.Value;
            product.OrderId = null;
            productsWithoutOrder.Add(product);

            BindProductsWithOrders(orderId);
            BindProductsWithoutOrders();
        }

        private void fakturujButton_Click(object sender, EventArgs e)
        {
            if (zamowieniaBindingSource.Current == null) return;

            try
            {
                Cursor = Cursors.WaitCursor;

                DataRowView z = (DataRowView)zamowieniaBindingSource.Current;
                REKLAMADataSet.zamowieniaRow zamowienie = (REKLAMADataSet.zamowieniaRow)z.Row;

                InitIssueTables(zamowienie);

                string errorMessage = CzyMoznaZafakturowac(zamowienie, klient);

                if (errorMessage != string.Empty)
                {
                    MessageBox.Show(errorMessage, "Fakturowanie");
                    Cursor = Cursors.Default;
                    return;
                }

                InvoicingType invoicingType = GetInvoicingType(zamowienie);

                //List<IProduct> subscriptionsToInvoice = GetSubscriptionsToInvoice(productsWithOrder, invoicingType);
                List<IProduct> productsToInvoice = (List<IProduct>)rEKLAMADataGridView.DataSource;

                WystawFakture(zamowienie, klient, productsToInvoice, false);

                RestoreConnections();

                zamowieniaBindingSource.ResetBindings(false);

                fAKTURYBindingSource.MoveLast();
            }
            finally
            {
                Cursor = Cursors.Default;
            }
        }

        private static InvoicingType GetInvoicingType(REKLAMADataSet.zamowieniaRow zamowienie)
        {
            switch (zamowienie.rodzajFakturowania)
            {
                case 0:
                    return InvoicingType.OneMonth;
                case 1:
                    return InvoicingType.ThreeMonths;
                default:
                    return InvoicingType.All;

            }
        }

        private int WystawFakture(REKLAMADataSet.zamowieniaRow zamowienie, REKLAMADataSet.KLIENCIRow klientRow, List<IProduct> products, bool proforma)
        {
            int idNaglowka;

            try
            {
                SqlConnection conn = new SqlConnection(ConnString.getConnString().Value);

                fAKTURYTableAdapter.Connection = conn;
                emisjeTableAdapter.Connection = conn;
                zamowieniaTableAdapter.Connection = conn;
                fakturyDetailsTableAdapter.Connection = conn;
                rEKLAMATableAdapter.Connection = conn;
                wplatyTableAdapter.Connection = conn;

                conn.Open();

                SqlTransaction transaction = conn.BeginTransaction();
                fAKTURYTableAdapter.AttachTransaction(transaction);
                emisjeTableAdapter.AttachTransaction(transaction);
                zamowieniaTableAdapter.AttachTransaction(transaction);
                fakturyDetailsTableAdapter.AttachTransaction(transaction);
                rEKLAMATableAdapter.AttachTransaction(transaction);
                wplatyTableAdapter.AttachTransaction(transaction);


                REKLAMADataSet.FAKTURYRow naglowekFaktury = UtworzNaglowekFaktury(zamowienie, klientRow, proforma);

                try
                {
                    rEKLAMADataSet.FAKTURY.AddFAKTURYRow(naglowekFaktury);
                    PobierzOznaczEmisje(zamowienie, naglowekFaktury);

                    UtworzPozycjeFaktury(naglowekFaktury, klientRow, products);
                    DodajWplate(naglowekFaktury);

                    zamowienie.zafakturowano = true;
                    zamowienie.EndEdit();

                    fAKTURYTableAdapter.Update(rEKLAMADataSet.FAKTURY);
                    idNaglowka = naglowekFaktury.ID_FAKTURY;
                    emisjeTableAdapter.Update(rEKLAMADataSet.UKAZE_SIE_W_NR);
                    fakturyDetailsTableAdapter.Update(rEKLAMADataSet.FAKTURA_DETAILS);
                    wplatyTableAdapter.Update(rEKLAMADataSet.Wplaty);

                    ProductRepository productRepository = new ProductRepository(ConnString.getConnString().Value);
                    productRepository.UpdateInvoiceId(products, idNaglowka);

                    int il = (int)emisjeTableAdapter.iloscNiezafakturowanychEmisjiWZamowieniu(zamowienie.idZamowienia);
                    if (il == 0 && !proforma)
                    {
                        zamowienie.zafakturowanoWszystko = true;
                    }

                    zamowieniaTableAdapter.Update(rEKLAMADataSet.zamowienia);
                    rEKLAMATableAdapter.Update(rEKLAMADataSet.REKLAMA);

                    transaction.Commit();
                    dtpZmianaDaty.Value = DateTime.Today;
                }
                catch (Exception)
                {
                    transaction.Rollback();
                    //conn.Close();
                    rEKLAMADataSet.UKAZE_SIE_W_NR.Clear();
                    rEKLAMADataSet.DatyWydan.Clear();
                    rEKLAMADataSet.FAKTURA_DETAILS.Clear();
                    rEKLAMADataSet.Wplaty.Clear();
                    rEKLAMADataSet.FAKTURY.RemoveFAKTURYRow(naglowekFaktury);
                    fAKTURYBindingSource.ResetBindings(false);
                    fAKTURYDataGridView.Refresh();
                    throw;
                }
                finally
                {
                    if (conn.State == ConnectionState.Open)
                        conn.Close();
                }
            }
            finally
            {
                rEKLAMADataSet.UKAZE_SIE_W_NR.Clear();
                rEKLAMADataSet.DatyWydan.Clear();
                rEKLAMADataSet.FAKTURA_DETAILS.Clear();
                rEKLAMADataSet.Wplaty.Clear();
                fAKTURYBindingSource.ResetBindings(false);
                fAKTURYBindingSource.Sort = "NUMER";
                fAKTURYDataGridView.Refresh();
                zamowieniaBindingSource.ResetBindings(false);

            }

            return idNaglowka;
        }

        private void DodajWplate(REKLAMADataSet.FAKTURYRow naglowekFaktury)
        {
            REKLAMADataSet.WplatyRow wplata = rEKLAMADataSet.Wplaty.NewWplatyRow();
            wplata.idFaktury = naglowekFaktury.ID_FAKTURY;
            wplata.idZamowienia = naglowekFaktury.idZamowienia;
            rEKLAMADataSet.Wplaty.AddWplatyRow(wplata);
        }

        private void UtworzPozycjeFaktury(REKLAMADataSet.FAKTURYRow naglowekFaktury, REKLAMADataSet.KLIENCIRow klientRow, List<IProduct> productsToInvoice)
        {
            decimal bruttoWaluta = 0;

            foreach (REKLAMADataSet.UKAZE_SIE_W_NRRow em in rEKLAMADataSet.UKAZE_SIE_W_NR)
            {
                REKLAMADataSet.FAKTURA_DETAILSRow fakturaDetailsRow = rEKLAMADataSet.FAKTURA_DETAILS.NewFAKTURA_DETAILSRow();

                REKLAMADataSet.DatyWydanRow[] dataWydanTable =
                    (REKLAMADataSet.DatyWydanRow[])em.GetChildRows("UKAZE_SIE_W_NR_DatyWydan");
                REKLAMADataSet.DatyWydanRow dataWydania = dataWydanTable[0];

                REKLAMADataSet.REKLAMARow reklama = (REKLAMADataSet.REKLAMARow)em.GetParentRow("REKLAMA_UKAZE_SIE_W_NR");

                fakturaDetailsRow.ROK = Convert.ToInt16(dataWydania.rok);
                fakturaDetailsRow.MIESIAC = Convert.ToInt16(dataWydania.ms);
                fakturaDetailsRow.TYTUL = Convert.ToInt16(dataWydania.idTytulu);
                fakturaDetailsRow.NAZWA_USLUGI = reklama.ID_REKLAMY + " | " + em.Nr_Wydania;
                fakturaDetailsRow.reklamaId = reklama.ReklamaID;
                fakturaDetailsRow.NR_WYDANIA = em.Nr_Wydania;

                fakturaDetailsRow.CENA_JEDN = Math.Round(Convert.ToDecimal(reklama.CENA_JEDN), 2);
                fakturaDetailsRow.ILOSC = 1;
                fakturaDetailsRow.JM = "szt.";

                if (naglowekFaktury.Iswaluta_mianoNull() && klientRow.Country.ToUpper() == "POLSKA")
                {
                    fakturaDetailsRow.UPUST_NETTO = Math.Round(Convert.ToDecimal(reklama.RABAT) * fakturaDetailsRow.CENA_JEDN, 2);
                    fakturaDetailsRow.UPUST_PR = reklama.RABAT;
                    decimal netto = (1 - Convert.ToDecimal(reklama.RABAT)) * fakturaDetailsRow.CENA_JEDN;

                    if (reklama.wyroznienie)
                        netto = Convert.ToDecimal(1 + reklama.wyroznienie_procent) * netto;

                    fakturaDetailsRow.NETTO = Math.Round(netto, 2);
                    fakturaDetailsRow.S_VAT = reklama.VAT;
                    decimal vat = Convert.ToDecimal(reklama.VAT);
                    fakturaDetailsRow.VAT = Convert.ToDecimal(vat * netto);
                    fakturaDetailsRow.BRUTTO = Convert.ToDecimal((1 + vat) * netto);
                }
                else if (naglowekFaktury.Iswaluta_mianoNull() && klientRow.Country.ToUpper() != "POLSKA")
                {
                    decimal vat = Convert.ToDecimal(reklama.VAT);
                    decimal netto = (1 - Convert.ToDecimal(reklama.RABAT)) * fakturaDetailsRow.CENA_JEDN;
                    if (reklama.wyroznienie)
                        netto = Convert.ToDecimal(1 + reklama.wyroznienie_procent) * netto;
                    fakturaDetailsRow.NETTO = Math.Round(netto, 2);
                    fakturaDetailsRow.S_VAT = reklama.VAT;
                    fakturaDetailsRow.BRUTTO = Convert.ToDecimal((1 + vat) * netto);

                    decimal brutto = fakturaDetailsRow.BRUTTO;

                    fakturaDetailsRow.VAT = Convert.ToDecimal(vat * brutto / (1 + vat));

                    fakturaDetailsRow.UPUST_PR = reklama.RABAT;
                    if (fakturaDetailsRow.UPUST_PR != 0)
                        fakturaDetailsRow.UPUST_NETTO = Math.Round(netto / (Convert.ToDecimal(reklama.RABAT) - netto), 2);
                    else
                        fakturaDetailsRow.UPUST_NETTO = 0;

                    fakturaDetailsRow.CENA_JEDN = Convert.ToDecimal(netto + fakturaDetailsRow.UPUST_NETTO);
                }
                else
                {
                    fakturaDetailsRow.BRUTTO = Convert.ToDecimal((reklama.Brutto_Euro / reklama.KROTNOŚĆ) * naglowekFaktury.waluta_kurs);
                    bruttoWaluta += Convert.ToDecimal(reklama.Brutto_Euro / reklama.KROTNOŚĆ);
                    fakturaDetailsRow.S_VAT = reklama.VAT;
                    decimal vat = Convert.ToDecimal(reklama.VAT);
                    decimal brutto = fakturaDetailsRow.BRUTTO;
                    fakturaDetailsRow.VAT = Convert.ToDecimal(vat * brutto / (1 + vat));
                    decimal netto = brutto - fakturaDetailsRow.VAT;
                    fakturaDetailsRow.NETTO = Math.Round(netto, 2);

                    fakturaDetailsRow.UPUST_PR = reklama.RABAT;
                    fakturaDetailsRow.UPUST_NETTO = fakturaDetailsRow.UPUST_PR != 0 ? Math.Round(netto / Convert.ToDecimal(reklama.RABAT) - netto, 2) : 0;

                    fakturaDetailsRow.CENA_JEDN = Convert.ToDecimal(netto + fakturaDetailsRow.UPUST_NETTO);
                }

                fakturaDetailsRow.TYP = 2;
                fakturaDetailsRow.PODTYP = 1;
                fakturaDetailsRow.ID_FAKTURY = naglowekFaktury.ID_FAKTURY;

                if (reklama.wyroznienie)
                {
                    fakturaDetailsRow.wyroznienie = true;
                }

                rEKLAMADataSet.FAKTURA_DETAILS.AddFAKTURA_DETAILSRow(fakturaDetailsRow);
            }

            foreach (IProduct subscription in productsToInvoice)
            {
                if (subscription.ProductType != ProductType.Subscription)
                    continue;

                // Księgowanie z rozbiciem na przyszłe okresy
                // Zostawiamy, bo może będziemy w przyszłości tak księgować
                //
                //foreach (IProductDetail subscriptionDetail in subscription.ProductDetails)
                //{
                //    REKLAMADataSet.FAKTURA_DETAILSRow fakturaDetailsRow = rEKLAMADataSet.FAKTURA_DETAILS.NewFAKTURA_DETAILSRow();

                //    fakturaDetailsRow.ROK = subscriptionDetail.Year;
                //    fakturaDetailsRow.MIESIAC = (short)subscriptionDetail.Month;
                //    //TODO: Add Title to Subscription schema
                //    fakturaDetailsRow.TYTUL = (short)subscription.TitleId;
                //    fakturaDetailsRow.NAZWA_USLUGI = subscription.ShortName + " | " + subscriptionDetail.Id;
                //    fakturaDetailsRow.reklamaId = subscription.Id;
                //    fakturaDetailsRow.CENA_JEDN = subscription.Price;
                //    fakturaDetailsRow.ILOSC = 1;
                //    fakturaDetailsRow.JM = "szt.";

                //    fakturaDetailsRow.NETTO = subscriptionDetail.PricePln;
                //    fakturaDetailsRow.BRUTTO = Math.Round(subscriptionDetail.PricePln * (1 + subscription.Vat));
                //    fakturaDetailsRow.S_VAT = (double)subscription.Vat;
                //    fakturaDetailsRow.VAT = Math.Round(subscriptionDetail.PricePln * subscription.Vat);

                //    //TODO: Get discount from parent
                //    //fakturaDetailsRow.UPUST_PR = subscription.Discount;
                //    //fakturaDetailsRow.UPUST_NETTO = fakturaDetailsRow.UPUST_PR != 0 ? Math.Round(netto / Convert.ToDecimal(reklama.RABAT) - netto, 2) : 0;

                //    fakturaDetailsRow.TYP = 1;
                //    fakturaDetailsRow.PODTYP = 1;
                //    fakturaDetailsRow.ID_FAKTURY = naglowekFaktury.ID_FAKTURY;

                //    rEKLAMADataSet.FAKTURA_DETAILS.AddFAKTURA_DETAILSRow(fakturaDetailsRow);

                //    if (subscription.Currency != "PLN")
                //        bruttoWaluta += subscriptionDetail.Price;
                //}

                //IProductDetail subscriptionDetail = subscription.ProductDetails[0];

                REKLAMADataSet.FAKTURA_DETAILSRow fakturaDetailsRow = rEKLAMADataSet.FAKTURA_DETAILS.NewFAKTURA_DETAILSRow();

                fakturaDetailsRow.ROK = DateTime.Now.Year;
                fakturaDetailsRow.MIESIAC = (short)naglowekFaktury.DATA_WYSTAWIENIA.Month;
                fakturaDetailsRow.TYTUL = (short)subscription.TitleId;
                fakturaDetailsRow.NAZWA_USLUGI = subscription.ShortName + " | " + subscription.Id;
                fakturaDetailsRow.reklamaId = subscription.Id;
                fakturaDetailsRow.JM = "szt.";
                fakturaDetailsRow.TYP = (short)subscription.ProductType;
                fakturaDetailsRow.PODTYP = 1;
                fakturaDetailsRow.ID_FAKTURY = naglowekFaktury.ID_FAKTURY;

                fakturaDetailsRow.ILOSC = subscription.DetailCount;
                fakturaDetailsRow.UPUST_PR = (double)subscription.Discount;
                fakturaDetailsRow.S_VAT = (double)subscription.Vat;

                //cena w walucie
                fakturaDetailsRow.CENA_JEDN = Math.Round(subscription.Price * fakturaDetailsRow.ILOSC * (1 - (decimal)fakturaDetailsRow.UPUST_PR), 2);

                //cena w PLN
                fakturaDetailsRow.NETTO = Math.Round(fakturaDetailsRow.CENA_JEDN * (decimal)naglowekFaktury.waluta_kurs, 2);
                fakturaDetailsRow.BRUTTO = Math.Round(fakturaDetailsRow.NETTO * (1 + subscription.Vat), 2);
                fakturaDetailsRow.VAT = Math.Round(fakturaDetailsRow.NETTO * subscription.Vat);
                fakturaDetailsRow.UPUST_NETTO = Math.Round(fakturaDetailsRow.NETTO * (decimal)fakturaDetailsRow.UPUST_PR, 2);

                rEKLAMADataSet.FAKTURA_DETAILS.AddFAKTURA_DETAILSRow(fakturaDetailsRow);

                if (subscription.Currency != "PLN")
                    bruttoWaluta += fakturaDetailsRow.CENA_JEDN;
            }

            if (bruttoWaluta != 0)
            {
                naglowekFaktury.waluta_brutto = Math.Round(Convert.ToDouble(bruttoWaluta), 2);
                naglowekFaktury.EndEdit();
            }
        }

        private void InitIssueTables(REKLAMADataSet.zamowieniaRow zamowienie)
        {
            emisjeTableAdapter.ClearBeforeFill = false;
            datyWydanTableAdapter.ClearBeforeFill = false;
            rEKLAMADataSet.UKAZE_SIE_W_NR.Clear();
            rEKLAMADataSet.DatyWydan.Clear();
            rEKLAMATableAdapter.FillByIdZamowienia(rEKLAMADataSet.REKLAMA, zamowienie.idZamowienia);

            REKLAMADataSet.DatyWydanDataTable t = datyWydanTableAdapter.GetDataByPierwszaEmisjaWZamowieniu(zamowienie.idZamowienia);
            if (t.Rows.Count <= 0) return;

            DateTime d = t[0].DATA_W;

            foreach (REKLAMADataSet.REKLAMARow reklama in rEKLAMADataSet.REKLAMA.Rows)
            {
                switch (zamowienie.rodzajFakturowania)
                {
                    //3m
                    case 1:
                        emisjeTableAdapter.FillByNiezafakturowane3MSRekID(
                            rEKLAMADataSet.UKAZE_SIE_W_NR,
                            reklama.ReklamaID,
                            d);
                        datyWydanTableAdapter.FillByReklamaId(rEKLAMADataSet.DatyWydan, reklama.ReklamaID);
                        break;
                    //calosc
                    case 2:
                        emisjeTableAdapter.FillByNiezafakturowane(rEKLAMADataSet.UKAZE_SIE_W_NR, reklama.ReklamaID);
                        datyWydanTableAdapter.FillByReklamaId(rEKLAMADataSet.DatyWydan, reklama.ReklamaID);
                        break;
                    //1ms
                    default:
                        emisjeTableAdapter.FillByNiezafakturowane1MSrekId(
                            rEKLAMADataSet.UKAZE_SIE_W_NR,
                            reklama.ReklamaID,
                            d);
                        datyWydanTableAdapter.FillByReklamaId(rEKLAMADataSet.DatyWydan, reklama.ReklamaID);
                        break;
                }

                // ustawiane by pozniej blokowac mozliwosc zmiany rabatu itp.
                reklama.FAKTURA_WYSTAWIONO = true;
                reklama.EndEdit();
            }
        }

        private void PobierzOznaczEmisje(REKLAMADataSet.zamowieniaRow zamowienie, REKLAMADataSet.FAKTURYRow naglowekFaktury)
        {
            if (zamowienie.IsdataOstatniejZafakturowanejEmisjiNull())
            {
                zamowienie.dataOstatniejZafakturowanejEmisji = DateTime.Today.AddMonths(-1);
            }

            foreach (REKLAMADataSet.REKLAMARow reklama in rEKLAMADataSet.REKLAMA.Rows)
            {
                foreach (DataRow em in rEKLAMADataSet.UKAZE_SIE_W_NR)
                {
                    REKLAMADataSet.UKAZE_SIE_W_NRRow emisja = (REKLAMADataSet.UKAZE_SIE_W_NRRow)em;
                    emisja.idFaktury = naglowekFaktury.ID_FAKTURY;
                    emisja.zafakturowana = true;

                    if (emisja.ReklamaId == reklama.ReklamaID)
                    {
                        reklama.FAKTURA_WYSTAWIONO = true;

                        if (naglowekFaktury.Iswaluta_mianoNull())
                        {
                            emisja.netto = Convert.ToDecimal(reklama.CENA_JEDN * (1 - reklama.RABAT));
                            if (reklama.wyroznienie)
                            {
                                emisja.netto = Math.Round(Convert.ToDecimal(1 + reklama.wyroznienie_procent) * emisja.netto, 2);
                            }
                        }
                        else
                        {
                            decimal temp = Math.Round(
                                Convert.ToDecimal(reklama.Brutto_Euro * naglowekFaktury.waluta_kurs / naglowekFaktury.waluta_przelicznik), 2);
                            emisja.netto = Convert.ToDecimal(temp / reklama.KROTNOŚĆ);
                        }

                        emisja.netto = Math.Round(emisja.netto, 2);
                    }

                    REKLAMADataSet.DatyWydanRow[] dataWydanTable =
                                       (REKLAMADataSet.DatyWydanRow[])em.GetChildRows("UKAZE_SIE_W_NR_DatyWydan");
                    REKLAMADataSet.DatyWydanRow dataWydania = dataWydanTable[0];

                    if (dataWydania.DATA_W > zamowienie.dataOstatniejZafakturowanejEmisji)
                    {
                        zamowienie.dataOstatniejZafakturowanejEmisji = dataWydania.DATA_W;
                    }
                }
            }

            zamowienie.EndEdit();
        }

        private REKLAMADataSet.FAKTURYRow UtworzNaglowekFaktury(REKLAMADataSet.zamowieniaRow zamowienie, REKLAMADataSet.KLIENCIRow klientRow, bool proforma)
        {
            List<IProduct> productsInOrder = (List<IProduct>)rEKLAMADataGridView.DataSource;

            //REKLAMADataSet.REKLAMARow reklama = (REKLAMADataSet.REKLAMARow)rEKLAMADataSet.REKLAMA.Rows[0];
            //Title title = _titles.Find(delegate(Title t) { return t.ShortName == reklama.TYTUŁ; });
            Title title = _titles.Find(delegate(Title t) { return t.Id == productsInOrder[0].TitleId; });
            IInvoiceProvider accountSystemProvider = InvoiceProviderFactory.GetInvoiceProviderById(title.InvoiceProvider);
            
            SLOWNIKDataSet.AGENCIRow agent = (SLOWNIKDataSet.AGENCIRow)agenciTableAdapter.GetDataByKodAgenta(zamowienie.kodAgenta).Rows[0];
            IInvoiceProvider invoiceDataProvider = InvoiceProviderFactory.GetInvoiceProviderById(agent.InvoiceProviderId);

            REKLAMADataSet.FAKTURYRow naglowekFaktury = (REKLAMADataSet.FAKTURYRow)rEKLAMADataSet.FAKTURY.NewRow();
            naglowekFaktury.KOREKTA = false;
            naglowekFaktury.idZamowienia = zamowienie.idZamowienia;
            naglowekFaktury.NUMER_ROZ = zamowienie.kodAgenta;
            naglowekFaktury.NUMER = proforma ? zamowienie.nrZamowienia : DbUtils.numerNowejFaktury(naglowekFaktury.NUMER_ROZ, DateTime.Today.Year, accountSystemProvider.SystemKsiegowyId);

            naglowekFaktury.NUMER_ROK = DateTime.Today.Year;
            naglowekFaktury.DATA_WYSTAWIENIA = DateTime.Today;

            //TODO: pass issueDate as parameter
            if (dtpZmianaDaty.Value != DateTime.Today && User.Instance().IsKierownik)
                naglowekFaktury.DATA_WYSTAWIENIA = dtpZmianaDaty.Value;

            SLOWNIKDataSet.AGENCJERow agencja = (SLOWNIKDataSet.AGENCJERow)agencjeTableAdapter.GetDataByKodAgenta(zamowienie.kodAgenta).Rows[0];
            naglowekFaktury.ID_SPRZEDAWCY = agencja.Id_agencji;

            naglowekFaktury.SPRZEDAWCA_ADRES = accountSystemProvider.GetAddress();
            naglowekFaktury.SPRZEDAWCA_NIP = accountSystemProvider.TaxNumber;
            
            //Katowice i Poznan
            if (naglowekFaktury.ID_SPRZEDAWCY == 4 || naglowekFaktury.ID_SPRZEDAWCY == 6 ||
                naglowekFaktury.ID_SPRZEDAWCY == 1223940400)
            {
                naglowekFaktury.EKSPORT = true;
                naglowekFaktury.SPRZEDAWCA_ADRES = invoiceDataProvider.GetAddress();
                naglowekFaktury.SPRZEDAWCA_NIP = invoiceDataProvider.TaxNumber;
            }

            naglowekFaktury.MIEJSCOWOSC_WYSTAWIENIA = agencja.miasto;
            naglowekFaktury.SystemKsiegowyId = Convert.ToByte(accountSystemProvider.SystemKsiegowyId);
            naglowekFaktury.PODPIS_WYSTAWIL = agent.Imię + " " + agent.Nazwisko;
            naglowekFaktury.DATA_SPRZEDAZY = naglowekFaktury.DATA_WYSTAWIENIA;

            naglowekFaktury.ID_NABYWCY = klientRow.CustomerID;
            naglowekFaktury.NABYWCA_ADRES = klientRow.Adres_Fkatura;
            naglowekFaktury.NABYWCA_NIP = klientRow.Nip;
            naglowekFaktury.opis = "Faktura za reklamy zgodnie z zamówieniem: "
                                                + klientRow.kodKlienta +
                                                "/" + zamowienie.nrZamowienia +
                                                "/" + zamowienie.kodAgenta +
                                                "/" + zamowienie.rokZamowienia;

            naglowekFaktury.SPOSOB_ZAPLATY = FakturaHelper.GetPaymentType(zamowienie.sposobZaplaty);
            naglowekFaktury.TERMIN_ZAPLATY = naglowekFaktury.DATA_SPRZEDAZY.AddDays(zamowienie.czasPlatnosci);
            naglowekFaktury.ZAPLACONO = false;

            naglowekFaktury.FAKTURA_TYP = 2;
            naglowekFaktury.FAKTURA_PODTYP = 1;

            naglowekFaktury.ID_KONTA = Convert.ToInt16(zamowienie.idKonta);
            naglowekFaktury.waluta_kurs = 1d;
            //WALUTOWE
            //if (!rEKLAMADataSet.REKLAMA[0].IsBrutto_Euro_MianoNull() && rEKLAMADataSet.REKLAMA[0].Brutto_Euro_Miano != string.Empty)
            if (productsInOrder[0].Currency != "PLN")
            {
                naglowekFaktury.SPRZEDAWCA_NIP = invoiceDataProvider.TaxCountryPrefix + " " + invoiceDataProvider.TaxNumber; //agencja.vies;
                naglowekFaktury.NABYWCA_NIP = klientRow.nipKraj + " " + klientRow.Nip;
                //naglowekFaktury.waluta_miano = rEKLAMADataSet.REKLAMA[0].Brutto_Euro_Miano;
                naglowekFaktury.waluta_miano = productsInOrder[0].Currency;

                DateTime dataPublikacji = naglowekFaktury.DATA_WYSTAWIENIA;

                SLOWNIKDataSet.Kursy_WalutDataTable kurs = kursyWalutTableAdapter.GetDataByDataPublikacji(
                     naglowekFaktury.waluta_miano, dataPublikacji);

                if (kurs.Count == 0) throw new ApplicationException("Błąd przy pobieraniu kursu waluty.");

                naglowekFaktury.waluta_kurs = User.Instance().IdAgencji == 6 ? kurs[0].Kurs_Sredni_Poznan : kurs[0].Kurs_Sredni;
                naglowekFaktury.waluta_kurs_z_dnia = kurs[0].Data_Publikacji;
                naglowekFaktury.waluta_przelicznik = kurs[0].przelicznik;
                naglowekFaktury.waluta_tabela_nr = kurs[0].Numer_Tabeli;
            }
            // jesli klientRow jest zagraniczny a waluta ciagle PLN
            else if (klientRow.Country.ToUpper() != "POLSKA")
            {
                naglowekFaktury.SPRZEDAWCA_NIP = invoiceDataProvider.TaxCountryPrefix + " " + invoiceDataProvider.TaxNumber;
                naglowekFaktury.NABYWCA_NIP = klientRow.nipKraj + " " + klientRow.Nip;
            }

            naglowekFaktury.EndEdit();
            return naglowekFaktury;
        }

        private string CzyMoznaZafakturowac(REKLAMADataSet.zamowieniaRow zamowienie, REKLAMADataSet.KLIENCIRow klientRow)
        {
            string errorMessage = string.Empty;

            errorMessage += zamowienie.zafakturowanoWszystko ? "Nie ma co fakturowac! \n" : "";
            errorMessage += zamowienie.IsrodzajFakturowaniaNull() ? "Nie wybrano sposobu fakturowania. \n" : "";
            errorMessage += zamowienie.IsidKontaNull() ? "Nie wybrano konta. \n" : "";
            errorMessage += zamowienie.IssposobZaplatyNull() ? "Nie wybrano sposobu zapłaty. \n" : "";
            errorMessage += klientRow.IsCountryNull() || string.IsNullOrEmpty(klientRow.Country) ? "Brak państwa klienta. \n" : "";
            errorMessage += klientRow.IsAdres_FkaturaNull() || string.IsNullOrEmpty(klientRow.Adres_Fkatura) ? "Brak adresu faktury klienta. \n" : "";
            errorMessage += klientRow.IsNipNull() || string.IsNullOrEmpty(klientRow.Nip) ? "Brak nipu klienta. \n" : "";

            if (!klientRow.IsCountryNull() && klientRow.Country != "Polska")
                errorMessage += klientRow.IsnipKrajNull() || string.IsNullOrEmpty(klientRow.nipKraj) ? "Brak symbolu kraju w nipie klienta. \n" : "";

            List<IProduct> productsInOrder = (List<IProduct>)rEKLAMADataGridView.DataSource;

            if (productsInOrder.Count == 0)
                errorMessage += "Proszę dodać przynajmniej jeden produkt do zamówienia \n";

            bool bIsAdvertisment = false;
            bool bIsSubscription = false;

            foreach (IProduct pr in productsInOrder)
            {
                if (pr.ProductType == ProductType.Advertisment)
                {
                    bIsAdvertisment = true;
                    if (bIsSubscription)
                        break;
                }
                else if (pr.ProductType == ProductType.Subscription)
                {
                    bIsSubscription = true;
                    if (bIsAdvertisment)
                        break;
                }
            }

            if (bIsAdvertisment)
            {
                if (rEKLAMADataSet.REKLAMA.Rows.Count <= 0)
                {
                    // try to load the ads once again in case something went wrong before...
                    rEKLAMATableAdapter.FillByIdZamowienia(rEKLAMADataSet.REKLAMA, zamowienie.idZamowienia);

                    if (rEKLAMADataSet.REKLAMA.Rows.Count <= 0)
                        errorMessage += "Proszę dodać przynajmniej jedną reklamę do zamówienia \n";
                }

                if (rEKLAMADataSet.REKLAMA.Select("[ZATWIERDZONO DO DRUKU] = 0").Length > 0)
                    errorMessage += "W zamówieniu są reklamy niezatwierdzone do druku \n";

                if (errorMessage.Length > 0)
                    return errorMessage;

                if (rEKLAMADataSet.UKAZE_SIE_W_NR.Rows.Count <= 0)
                {
                    errorMessage += "Nie znaleziono żadnych emisji do zafakturowania \n";
                    return errorMessage;
                }

                REKLAMADataSet.DatyWydanDataTable t = datyWydanTableAdapter.GetDataByPierwszaEmisjaWZamowieniu(zamowienie.idZamowienia);
                if (t.Rows.Count == 0)
                    errorMessage += "Nie znaleziono żadnych emisji do zafakturowania \n";
            }

            if (bIsSubscription)
            {
                //TODO: walidacja abonamentów
            }

            return errorMessage;
        }

        private void WydrukButton_Click(object sender, EventArgs e)
        {
            if (zamowieniaBindingSource.Current != null)
            {
                DataRowView z = (DataRowView)zamowieniaBindingSource.Current;
                REKLAMADataSet.zamowieniaRow zamowienie = (REKLAMADataSet.zamowieniaRow)z.Row;

                OrderViewer ov = new OrderViewer(zamowienie.idZamowienia, 9);
                ov.ShowDialog();
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (fAKTURYBindingSource.Current != null)
            {
                REKLAMADataSet.FAKTURYRow row =
                    (REKLAMADataSet.FAKTURYRow)
                    ((DataRowView)fAKTURYBindingSource.Current).Row;

                if (row.IsidFakturyKorektaNull())
                {
                    FactureViewer fv = new FactureViewer(row.ID_FAKTURY, false);
                    fv.ShowDialog();
                }
                else
                {
                    FactureViewer fv = new FactureViewer(row.ID_FAKTURY, row.idFakturyVAT, row.idFakturyKorekta);
                    fv.ShowDialog();
                }
            }
        }

        private void delOrderBtn_Click(object sender, EventArgs e)
        {
            //if (rEKLAMADataSet.REKLAMA.Rows.Count == 0 && rEKLAMADataSet.FAKTURY.Rows.Count == 0)
            if (((List<IProduct>)rEKLAMADataGridView.DataSource).Count == 0 && rEKLAMADataSet.FAKTURY.Rows.Count == 0)
            {
                zamowieniaBindingSource.Remove(zamowieniaBindingSource.Current);
                zamowieniaBindingSource.EndEdit();
                zamowieniaTableAdapter.Update(rEKLAMADataSet.zamowienia);
            }
            else
            {
                MessageBox.Show("Nie można usunąć zamówienia.");
            }
        }

        private void korektaButton_Click(object sender, EventArgs e)
        {
            if (fAKTURYBindingSource.Current != null &&
                zamowieniaBindingSource.Current != null)
            {
                Cursor = Cursors.WaitCursor;

                DataRowView row = (DataRowView)fAKTURYBindingSource.Current;
                REKLAMADataSet.FAKTURYRow faktura = (REKLAMADataSet.FAKTURYRow)row.Row;

                if (Convert.ToBoolean(faktura.KOREKTA))
                {
                    MessageBox.Show("Nie można wystawić korekty do korekty");
                    Cursor = Cursors.Default;
                    return;
                }

                //sprawdzenie czy korekta nie byla juz wystawiona
                if (!faktura.IsID_FK_KORNull())
                {
                    MessageBox.Show("Istnieje już faktura korekta");

                    //return było zablokowane
                    Cursor = Cursors.Default;
                    return;
                }

                try
                {
                    int idZam = (int)((DataRowView)zamowieniaBindingSource.Current).Row["idZamowienia"];

                    REKLAMADataSet.FAKTURYRow naglowekKorekty = utworzNaglowekKorekty(faktura);

                    pobierzEmisjeDoKorekty(faktura, idZam);
                    utworzPozycjeFakturyKorekty(naglowekKorekty);

                    if (!faktura.IsID_FK_KORNull())
                    {
                        naglowekKorekty.idFakturyKorekta = faktura.ID_FK_KOR;
                    }

                    SqlConnection conn = new SqlConnection(ConnString.getConnString().Value);

                    fAKTURYTableAdapter.Connection = conn;
                    emisjeTableAdapter.Connection = conn;
                    zamowieniaTableAdapter.Connection = conn;
                    fakturyDetailsTableAdapter.Connection = conn;
                    rEKLAMATableAdapter.Connection = conn;

                    conn.Open();

                    SqlTransaction transaction = conn.BeginTransaction();
                    fAKTURYTableAdapter.AttachTransaction(transaction);
                    emisjeTableAdapter.AttachTransaction(transaction);
                    zamowieniaTableAdapter.AttachTransaction(transaction);
                    fakturyDetailsTableAdapter.AttachTransaction(transaction);
                    rEKLAMATableAdapter.AttachTransaction(transaction);

                    try
                    {
                        fAKTURYTableAdapter.Update(rEKLAMADataSet.FAKTURY);

                        faktura.ID_FK_KOR = naglowekKorekty.ID_FAKTURY;
                        faktura.EndEdit();

                        fAKTURYTableAdapter.Update(rEKLAMADataSet.FAKTURY);

                        emisjeTableAdapter.Update(rEKLAMADataSet.UKAZE_SIE_W_NR);
                        fakturyDetailsTableAdapter.Update(rEKLAMADataSet.FAKTURA_DETAILS);
                        zamowieniaTableAdapter.Update(rEKLAMADataSet.zamowienia);

                        transaction.Commit();
                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        conn.Close();
                        throw;
                    }
                }
                finally
                {
                    rEKLAMADataSet.UKAZE_SIE_W_NR.Clear();
                    rEKLAMADataSet.DatyWydan.Clear();
                    rEKLAMADataSet.FAKTURA_DETAILS.Clear();
                    fAKTURYBindingSource.ResetBindings(false);
                    fAKTURYDataGridView.Refresh();
                    Cursor = Cursors.Default;
                }
            }

            RestoreConnections();
        }

        private REKLAMADataSet.FAKTURYRow utworzNaglowekKorekty(REKLAMADataSet.FAKTURYRow faktura)
        {
            REKLAMADataSet.FAKTURYRow naglowekKorekty = rEKLAMADataSet.FAKTURY.NewFAKTURYRow();
            naglowekKorekty.KOREKTA = true;
            //  naglowekKorekty.EKSPORT = true;

            naglowekKorekty.idZamowienia = faktura.idZamowienia;
            naglowekKorekty.idFakturyKorekta = faktura.ID_FAKTURY;
            naglowekKorekty.idFakturyVAT = faktura.ID_FAKTURY;

            naglowekKorekty.NUMER_ROZ = faktura.NUMER_ROZ;
            naglowekKorekty.NUMER = FakturaHelper.GetNewCorrectionInvoiceNumber(DateTime.Today.Year, faktura.SystemKsiegowyId);
            naglowekKorekty.NUMER_ROK = DateTime.Today.Year;
            naglowekKorekty.DATA_WYSTAWIENIA = DateTime.Today;

            naglowekKorekty.ID_SPRZEDAWCY = faktura.ID_SPRZEDAWCY;

            if (naglowekKorekty.ID_SPRZEDAWCY == 4 || naglowekKorekty.ID_SPRZEDAWCY == 6 ||
                naglowekKorekty.ID_SPRZEDAWCY == 1223940400)
            {
                naglowekKorekty.EKSPORT = true;
            }

            naglowekKorekty.MIEJSCOWOSC_WYSTAWIENIA = faktura.MIEJSCOWOSC_WYSTAWIENIA;
            naglowekKorekty.SPRZEDAWCA_ADRES = faktura.SPRZEDAWCA_ADRES;
            naglowekKorekty.SPRZEDAWCA_NIP = faktura.SPRZEDAWCA_NIP;
            naglowekKorekty.SystemKsiegowyId = faktura.SystemKsiegowyId;

            naglowekKorekty.PODPIS_WYSTAWIL = faktura.PODPIS_WYSTAWIL;
            naglowekKorekty.DATA_SPRZEDAZY = DateTime.Today;

            naglowekKorekty.ID_NABYWCY = faktura.ID_NABYWCY;
            naglowekKorekty.NABYWCA_ADRES = faktura.NABYWCA_ADRES;
            naglowekKorekty.NABYWCA_NIP = faktura.NABYWCA_NIP;
            naglowekKorekty.TERMIN_ZAPLATY = DateTime.Today.AddDays(7);
            naglowekKorekty.opis = "rezygnacja z emisji reklamy";

            naglowekKorekty.SPOSOB_ZAPLATY = faktura.SPOSOB_ZAPLATY;

            naglowekKorekty.TERMIN_ZAPLATY = faktura.TERMIN_ZAPLATY;
            naglowekKorekty.ZAPLACONO = false;

            naglowekKorekty.FAKTURA_TYP = 2;
            naglowekKorekty.FAKTURA_PODTYP = 1;

            naglowekKorekty.ID_KONTA = faktura.ID_KONTA;

            if (!faktura.Iswaluta_mianoNull())
            {
                naglowekKorekty.SPRZEDAWCA_NIP = faktura.SPRZEDAWCA_NIP;
                naglowekKorekty.NABYWCA_NIP = faktura.NABYWCA_NIP;
                naglowekKorekty.waluta_miano = faktura.waluta_miano;

                naglowekKorekty.waluta_kurs = faktura.waluta_kurs;
                naglowekKorekty.waluta_kurs_z_dnia = faktura.waluta_kurs_z_dnia;
                naglowekKorekty.waluta_przelicznik = faktura.waluta_przelicznik;
                naglowekKorekty.waluta_tabela_nr = faktura.waluta_tabela_nr;
            }

            rEKLAMADataSet.FAKTURY.AddFAKTURYRow(naglowekKorekty);

            return naglowekKorekty;
        }

        private void pobierzEmisjeDoKorekty(REKLAMADataSet.FAKTURYRow naglowekFaktury, int idZam)
        {
            emisjeTableAdapter.ClearBeforeFill = false;
            datyWydanTableAdapter.ClearBeforeFill = false;
            rEKLAMATableAdapter.ClearBeforeFill = false;

            emisjeTableAdapter.FillByIdFaktury(rEKLAMADataSet.UKAZE_SIE_W_NR, naglowekFaktury.ID_FAKTURY);
            rEKLAMATableAdapter.FillByIdZamowienia(rEKLAMADataSet.REKLAMA, idZam);
            rEKLAMATableAdapter.FillByIdFaktury(rEKLAMADataSet.REKLAMA, naglowekFaktury.ID_FAKTURY);

            datyWydanTableAdapter.FillByIdFaktury(rEKLAMADataSet.DatyWydan, naglowekFaktury.ID_FAKTURY);
        }

        private void utworzPozycjeFakturyKorekty(REKLAMADataSet.FAKTURYRow naglowekFaktury)
        {
            decimal brutto_waluta = 0;

            foreach (REKLAMADataSet.UKAZE_SIE_W_NRRow em in rEKLAMADataSet.UKAZE_SIE_W_NR)
            {
                if (em.status != 2)
                {
                    REKLAMADataSet.FAKTURA_DETAILSRow fakturaDetailsRow = rEKLAMADataSet.FAKTURA_DETAILS.NewFAKTURA_DETAILSRow();

                    REKLAMADataSet.DatyWydanRow[] dataWydanTable =
                        (REKLAMADataSet.DatyWydanRow[])em.GetChildRows("UKAZE_SIE_W_NR_DatyWydan");
                    REKLAMADataSet.DatyWydanRow dataWydania = dataWydanTable[0];

                    REKLAMADataSet.REKLAMARow reklama = (REKLAMADataSet.REKLAMARow)em.GetParentRow("REKLAMA_UKAZE_SIE_W_NR");

                    fakturaDetailsRow.ROK = Convert.ToInt16(dataWydania.rok);

                    fakturaDetailsRow.MIESIAC = Convert.ToInt16(dataWydania.ms);
                    fakturaDetailsRow.TYTUL = Convert.ToInt16(dataWydania.idTytulu);
                    fakturaDetailsRow.NAZWA_USLUGI = reklama.ID_REKLAMY + " | " + em.Nr_Wydania;
                    fakturaDetailsRow.reklamaId = reklama.ReklamaID;
                    fakturaDetailsRow.NR_WYDANIA = em.Nr_Wydania;

                    fakturaDetailsRow.CENA_JEDN = Convert.ToDecimal(reklama.CENA_JEDN);
                    fakturaDetailsRow.ILOSC = 1;
                    fakturaDetailsRow.JM = "szt.";

                    if (naglowekFaktury.Iswaluta_mianoNull())
                    {
                        fakturaDetailsRow.UPUST_NETTO = Convert.ToDecimal(reklama.RABAT) * fakturaDetailsRow.CENA_JEDN;
                        fakturaDetailsRow.UPUST_PR = reklama.RABAT;
                        decimal netto = (1 - Convert.ToDecimal(reklama.RABAT)) * fakturaDetailsRow.CENA_JEDN;
                        fakturaDetailsRow.NETTO = netto;
                        fakturaDetailsRow.S_VAT = reklama.VAT;
                        decimal _vat = Convert.ToDecimal(reklama.VAT);
                        fakturaDetailsRow.VAT = Convert.ToDecimal(Math.Round(_vat * netto, 2));
                        fakturaDetailsRow.BRUTTO = Convert.ToDecimal(Math.Round((1 + _vat) * netto, 2));
                    }
                    else
                    {
                        //int krotnosc = this.rEKLAMADataSet.UKAZE_SIE_W_NR.PoliczAktywne(reklama.ReklamaID);

                        fakturaDetailsRow.BRUTTO = Convert.ToDecimal((reklama.Brutto_Euro / reklama.KROTNOŚĆ) * naglowekFaktury.waluta_kurs);
                        brutto_waluta += Convert.ToDecimal(reklama.Brutto_Euro / reklama.KROTNOŚĆ);
                        fakturaDetailsRow.S_VAT = reklama.VAT;
                        decimal _vat = Convert.ToDecimal(reklama.VAT);
                        decimal brutto = fakturaDetailsRow.BRUTTO;
                        fakturaDetailsRow.VAT = Convert.ToDecimal(Math.Round(_vat * brutto / (1 + _vat), 2));
                        decimal netto = brutto - fakturaDetailsRow.VAT;
                        fakturaDetailsRow.NETTO = netto;
                        fakturaDetailsRow.UPUST_PR = reklama.RABAT;
                        if (fakturaDetailsRow.UPUST_PR != 0)
                        {
                            fakturaDetailsRow.UPUST_NETTO = netto / Convert.ToDecimal(reklama.RABAT) - netto;
                        }
                        else
                        {
                            fakturaDetailsRow.UPUST_NETTO = 0;
                        }

                        fakturaDetailsRow.CENA_JEDN = Convert.ToDecimal(netto + fakturaDetailsRow.UPUST_NETTO);
                    }

                    fakturaDetailsRow.TYP = 2;
                    fakturaDetailsRow.PODTYP = 1;
                    fakturaDetailsRow.ID_FAKTURY = naglowekFaktury.ID_FAKTURY;

                    if (reklama.wyroznienie)
                    {
                        fakturaDetailsRow.wyroznienie = true;
                    }

                    rEKLAMADataSet.FAKTURA_DETAILS.AddFAKTURA_DETAILSRow(fakturaDetailsRow);
                }
            }

            if (brutto_waluta != 0)
            {
                naglowekFaktury.waluta_brutto = Math.Round(Convert.ToDouble(brutto_waluta), 2);
                naglowekFaktury.EndEdit();
            }
        }

        private void fAKTURYDataGridView_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            foreach (DataGridViewRow row in fAKTURYDataGridView.Rows)
            {
                DataRowView r = (DataRowView)row.DataBoundItem;
                REKLAMADataSet.FAKTURYRow f = (REKLAMADataSet.FAKTURYRow)r.Row;
                if (!f.IsidFakturyKorektaNull())
                {
                    row.DefaultCellStyle.ForeColor = Color.Red;
                }
            }
        }

        private void korektaDoExportButton_Click(object sender, EventArgs e)
        {
            if (fAKTURYBindingSource.Current != null)
            {
                Cursor = Cursors.WaitCursor;

                DataRowView row = (DataRowView)fAKTURYBindingSource.Current;
                REKLAMADataSet.FAKTURYRow faktura = (REKLAMADataSet.FAKTURYRow)row.Row;

                if (Convert.ToBoolean(faktura.KOREKTA) && faktura.EKSPORT)
                {
                    faktura.EKSPORT = false;
                    fAKTURYBindingSource.EndEdit();
                    fAKTURYTableAdapter.Update(rEKLAMADataSet.FAKTURY);
                }

                Cursor = Cursors.Default;
            }
        }

        private void button6_Click(object sender, EventArgs e)
        {
            if (fAKTURYBindingSource.Current != null)
            {
                DataRowView row = (DataRowView)fAKTURYBindingSource.Current;
                REKLAMADataSet.FAKTURYRow f = (REKLAMADataSet.FAKTURYRow)row.Row;

                REKLAMADataSetTableAdapters.WplatyTableAdapter wplaty = new REKLAMADataSetTableAdapters.WplatyTableAdapter();
                wplaty.Connection.ConnectionString = ConnString.getConnString().Value;
                REKLAMADataSet.WplatyDataTable table = wplaty.GetDataByIdFaktury(f.ID_FAKTURY);

                PaymentForm2 pf2 = table.Count == 0 ? new PaymentForm2(0, f.ID_FAKTURY) : new PaymentForm2(table[0].idWplaty, f.ID_FAKTURY);

                pf2.ShowDialog();
            }
        }

        private bool EditSelGridProduct(DataGridView grid)
        {
            if (grid.SelectedRows.Count <= 0) return false;

            IProduct product = (IProduct)grid.SelectedRows[0].DataBoundItem;
            Form frm = null;

            if (product.ProductType == ProductType.Advertisment)
            {
                OrderDetails.getOrderDetails().PokazSzczegolyZamowienia(product.Id);
                frm = OrderDetails.getOrderDetails();
            }
            else
            {
                Subscription subscr = customerRepository.GetSubscription(product.Id);
                frm = new SubscriptionForm(subscr.CustomerId, subscr);
            }

            return frm.ShowDialog() == DialogResult.OK;
        }

        private void reklama1Button_Click(object sender, EventArgs e)
        {
            if (!EditSelGridProduct(rEKLAMADataGridView))
                return;

            IProduct product = (IProduct)rEKLAMADataGridView.SelectedRows[0].DataBoundItem;

            //refresh items
            productsWithOrder = customerRepository.FindProductsWithOrders(klient.CustomerID);
            BindProductsWithOrders(product.OrderId.Value);
        }

        private void reklama2Button_Click(object sender, EventArgs e)
        {
            if (!EditSelGridProduct(rEKLAMADataGridView1))
                return;

            //refresh items
            productsWithoutOrder = customerRepository.FindProductsWithoutOrders(klient.CustomerID);
            BindProductsWithoutOrders();
        }

        private void fAKTURYBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            if (fAKTURYBindingSource.Current == null) return;

            wplataButton.Enabled = !Convert.ToBoolean(((REKLAMADataSet.FAKTURYRow)((DataRowView)fAKTURYBindingSource.Current).Row).KOREKTA);
        }

        private void zamowieniaBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            if (zamowieniaBindingSource.Current == null) return;

            DataRowView z = (DataRowView)zamowieniaBindingSource.Current;
            REKLAMADataSet.zamowieniaRow zamowienie = (REKLAMADataSet.zamowieniaRow)z.Row;

            BindProductsWithOrders(zamowienie.idZamowienia);

            fAKTURYTableAdapter.FillByIdZamowienia(rEKLAMADataSet.FAKTURY, zamowienie.idZamowienia);

            dodajDoZamButton.Enabled = !zamowienie.zafakturowanoWszystko;
            usunZZamButton.Enabled = !zamowienie.zafakturowanoWszystko;
            fakturujButton.Enabled = !zamowienie.zafakturowanoWszystko;

            if (!zamowienie.IsdataOstatniejZafakturowanejEmisjiNull())
            {
                DateTime data = zamowienie.dataOstatniejZafakturowanejEmisji;
                DateTime dzis = DateTime.Today;

                if (dzis.Year > data.Year ||
                   (dzis.Year == data.Year && dzis.Month > data.Month))
                {
                    fakturujButton.Enabled = true;
                }
                else
                {
                    fakturujButton.Enabled = false;
                }
            }
        }

        private void usunFaktureButton_Click(object sender, EventArgs e)
        {
            if (fAKTURYBindingSource.Current == null) return;

            if (MessageBox.Show("Czy na pewno chcesz usunąć fakturę?",
                                                  "Faktura - usuwanie",
                                                  MessageBoxButtons.YesNo,
                                                  MessageBoxIcon.Question) != DialogResult.Yes)
                return;


            Cursor = Cursors.WaitCursor;

            REKLAMADataSet.FAKTURYRow faktura = (REKLAMADataSet.FAKTURYRow)((DataRowView)fAKTURYBindingSource.Current).Row;

            //jezeli jest korekta do tej faktury to nie mozna jej usunac
            if (!Convert.ToBoolean(faktura.KOREKTA) && !faktura.IsID_FK_KORNull())
            {
                MessageBox.Show("Istnieje korekta. Nie można usunąć faktury");
                return;
            }

            //jezeli jest korekta do tej korekty to nie mozna jej usunac
            if (Convert.ToBoolean(faktura.KOREKTA) && fAKTURYBindingSource.Find("idFakturyKorekta", faktura.ID_FAKTURY) > -1)
            {
                MessageBox.Show("Nie można usunąć faktury");
                return;
            }

            if (Convert.ToBoolean(faktura.KOREKTA))
                UsunKorekte(faktura);
            else
                UsunFakture(faktura);

            Cursor = Cursors.Default;
        }

        private void UsunKorekte(REKLAMADataSet.FAKTURYRow korekta)
        {
            int idKorekty = korekta.ID_FAKTURY;
            int idKorygowanejFaktury = korekta.idFakturyKorekta;
            int idZam = korekta.idZamowienia;

            int i = fAKTURYBindingSource.Find("ID_FK_KOR", idKorekty);

            REKLAMADataSet.FAKTURYRow korygowanaFaktura = (REKLAMADataSet.FAKTURYRow)
                ((DataRowView)fAKTURYBindingSource.List[i]).Row;

            int j = fAKTURYBindingSource.Find("ID_FAKTURY", idKorygowanejFaktury);

            if (j > -1 && i != j)
            {
                REKLAMADataSet.FAKTURYRow poprzedniaKorekta = (REKLAMADataSet.FAKTURYRow)
                    ((DataRowView)fAKTURYBindingSource.List[j]).Row;

                korygowanaFaktura.ID_FK_KOR = poprzedniaKorekta.ID_FAKTURY;
            }
            else
            {
                korygowanaFaktura.SetID_FK_KORNull();
            }

            fAKTURYBindingSource.EndEdit();

            SqlConnection conn = new SqlConnection(ConnString.getConnString().Value);

            fAKTURYTableAdapter.Connection = conn;
            fakturyDetailsTableAdapter.Connection = conn;

            conn.Open();
            SqlTransaction transaction = conn.BeginTransaction();

            fAKTURYTableAdapter.AttachTransaction(transaction);
            fakturyDetailsTableAdapter.AttachTransaction(transaction);

            try
            {
                fAKTURYTableAdapter.Update(rEKLAMADataSet.FAKTURY);
                fAKTURYTableAdapter.Delete(idKorekty);
                fakturyDetailsTableAdapter.Delete(idKorekty);

                transaction.Commit();
            }
            catch (Exception)
            {
                transaction.Rollback();
                throw;
            }
            finally
            {
                fAKTURYTableAdapter.FillByIdZamowienia(rEKLAMADataSet.FAKTURY, idZam);
                conn.Close();
            }
        }

        private void UsunFakture(REKLAMADataSet.FAKTURYRow faktura)
        {
            int idFakt = faktura.ID_FAKTURY;
            int idZam = faktura.idZamowienia;
            bool zmienReklamyOrazZamowienie = false;

            if (fAKTURYBindingSource.List.Count == 1)
                zmienReklamyOrazZamowienie = true;

            emisjeTableAdapter.ClearBeforeFill = false;
            emisjeTableAdapter.FillByIdFaktury(rEKLAMADataSet.UKAZE_SIE_W_NR, idFakt);

            foreach (DataRow r in rEKLAMADataSet.UKAZE_SIE_W_NR.Rows)
            {
                REKLAMADataSet.UKAZE_SIE_W_NRRow row = (REKLAMADataSet.UKAZE_SIE_W_NRRow)r;

                row.SetidFakturyNull();
                row.netto = 0;
                row.zafakturowana = false;
                row.EndEdit();
            }

            DataRowView zam = (DataRowView)zamowieniaBindingSource.Current;
            REKLAMADataSet.zamowieniaRow zamowienie =
                (REKLAMADataSet.zamowieniaRow)zam.Row;

            if (zmienReklamyOrazZamowienie)
            {
                foreach (DataRow r in rEKLAMADataSet.REKLAMA.Rows)
                {
                    REKLAMADataSet.REKLAMARow reklama = (REKLAMADataSet.REKLAMARow)r;
                    reklama.FAKTURA_WYSTAWIONO = false;
                    reklama.EndEdit();
                }
                zamowienie.zafakturowano = false;
            }
            //przy usuwaniu faktury zawsze ustaw to pole na false, poniewaz nie pozwala wystawic faktury
            zamowienie.zafakturowanoWszystko = false;
            zamowienie.SetdataOstatniejZafakturowanejEmisjiNull();
            zamowienie.EndEdit();

            SqlConnection conn = new SqlConnection(ConnString.getConnString().Value);

            fAKTURYTableAdapter.Connection = conn;
            emisjeTableAdapter.Connection = conn;
            zamowieniaTableAdapter.Connection = conn;
            fakturyDetailsTableAdapter.Connection = conn;
            rEKLAMATableAdapter.Connection = conn;
            wplatyTableAdapter.Connection = conn;

            conn.Open();
            SqlTransaction transaction = conn.BeginTransaction();

            fAKTURYTableAdapter.AttachTransaction(transaction);
            emisjeTableAdapter.AttachTransaction(transaction);
            zamowieniaTableAdapter.AttachTransaction(transaction);
            fakturyDetailsTableAdapter.AttachTransaction(transaction);
            rEKLAMATableAdapter.AttachTransaction(transaction);
            wplatyTableAdapter.AttachTransaction(transaction);

            try
            {
                fAKTURYTableAdapter.Delete(idFakt);
                fakturyDetailsTableAdapter.Delete(idFakt);
                wplatyTableAdapter.Delete(idFakt);
                emisjeTableAdapter.Update(rEKLAMADataSet.UKAZE_SIE_W_NR);
                zamowieniaTableAdapter.Update(rEKLAMADataSet.zamowienia);
                rEKLAMATableAdapter.Update(rEKLAMADataSet.REKLAMA);

                List<IProduct> products = (List<IProduct>)rEKLAMADataGridView.DataSource;
                ProductRepository productRepository = new ProductRepository(ConnString.getConnString().Value);
                productRepository.ClearInvoiceId(products);

                transaction.Commit();
            }
            catch
            {
                transaction.Rollback();
                throw;
            }
            finally
            {
                rEKLAMADataSet.UKAZE_SIE_W_NR.Clear();
                fAKTURYTableAdapter.FillByIdZamowienia(rEKLAMADataSet.FAKTURY, idZam);
                conn.Close();
            }
        }

        private void proformaButton_Click(object sender, EventArgs e)
        {
            if (zamowieniaBindingSource.Current == null) return;

            Cursor = Cursors.WaitCursor;

            DataRowView z = (DataRowView)zamowieniaBindingSource.Current;
            REKLAMADataSet.zamowieniaRow zamowienie = (REKLAMADataSet.zamowieniaRow)z.Row;

            InitIssueTables(zamowienie);

            string errorMessage = CzyMoznaZafakturowac(zamowienie, klient);

            if (errorMessage != string.Empty)
            {
                MessageBox.Show(errorMessage, "Fakturowanie - Proforma");
                Cursor = Cursors.Default;
                return;
            }

            int id = 0;
            try
            {
                InvoicingType invoicingType = GetInvoicingType(zamowienie);

                List<IProduct> subscriptionsToInvoice = GetSubscriptionsToInvoice(productsWithOrder, invoicingType);

                id = WystawFakture(zamowienie, klient, subscriptionsToInvoice, true);
                FactureViewer fv = new FactureViewer(id, true, klient.kodKlienta);
                fv.ShowDialog();
            }
            finally
            {
                DataRow[] rows = rEKLAMADataSet.FAKTURY.Select("id_faktury=" + id);
                if (rows.Length > 0)
                    UsunFakture((REKLAMADataSet.FAKTURYRow) rows[0]);
                
                RestoreConnections();
                Cursor = Cursors.Default;
            }
        }

        private void RestoreConnections()
        {
            fAKTURYTableAdapter.Connection = new SqlConnection(ConnString.getConnString().Value);
            emisjeTableAdapter.Connection = new SqlConnection(ConnString.getConnString().Value);
            zamowieniaTableAdapter.Connection = new SqlConnection(ConnString.getConnString().Value);
            fakturyDetailsTableAdapter.Connection = new SqlConnection(ConnString.getConnString().Value);
            rEKLAMATableAdapter.Connection = new SqlConnection(ConnString.getConnString().Value);
            wplatyTableAdapter.Connection = new SqlConnection(ConnString.getConnString().Value);
        }

        private List<IProduct> GetSubscriptionsToInvoice(List<IProduct> products, InvoicingType invoicingType)
        {
            ProductRepository productRepository = new ProductRepository(ConnString.getConnString().Value);
            List<IProduct> subscriptions = products.FindAll(delegate(IProduct p) { return p.ProductType == ProductType.Subscription; });
            
            if (subscriptions.Count == 0) return new List<IProduct>();
            
            DateTime date = productRepository.FindFirstDateForInvoice(subscriptions);
            
            if (date == DateTime.MinValue) return new List<IProduct>();
            
            List<IProduct> subscriptionsToInvoice = productRepository.FindProductsToInvoice(subscriptions, invoicingType, date);
            return subscriptionsToInvoice;
        }
    }
}