IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
Neaktivní uživatel:18.5.2013 14:50

Zdravím,

jedná se o mojí trochu smyslplnější aplikaci - kalkulačku daňových odpisů.
Rád bych se dozvěděl další názor, například hlavní nedostatky, případně jestli nedělám někde zásadní chyby.

Aplikace umí

  • vypočítat zrychlené a rovnoměrné odpisy dle zadaných údajů
  • exportovat do .txt a excelu

Do budoucna uvažuju například o:

  • přidání dalších parametrů
  • přidání seznamu majetku a ukládání/výpis odpisů podle něj (čímž dojde i k odpadnutí části proměnných)
  • přidání další nabídky pro rovnoměrné odpisování (např. související se zvýšenou vstupní cenou)
  • přidání tisku
  • vylepšení / dopracování uživatelského rozhraní, menu...

Link ke stažení:
http://uloz.to/…D/do2013-zip

zdrojový kód:

namespace Odpisovac
{
    public partial class Odpisovac : Form
    {

        /// <summary>
        /// Proměnná pro pořizovací cenu (zadanou uživatelem).
        /// </summary>
        private decimal cena;
        /// <summary>
        /// Proměnná pro zůstatkovou cenu.
        /// </summary>
        private decimal zcena;
        /// <summary>
        /// Proměnná pro počet let (dle odpisové třídy zadané uživatelem)
        /// </summary>
        private byte pocetLet;
        /// <summary>
        /// Proměnná pro rok pořízení majetku a začátku jeho odpisování (zadáná uživatelem).
        /// </summary>
        private int letopocet;
        /// <summary>
        /// Proměnná představující částku odpisu v daném roce.
        /// </summary>
        private decimal odpis;
        /// <summary>
        /// Promenná představující koeficient u rovnoměrných odpisů.
        /// </summary>
        private decimal koeficient;
        /// <summary>
        /// Řádek ve vystupListView.
        /// </summary>
        private ListViewItem item;
        /// <summary>
        /// Pole pro počty let odpisování definované zákonem dle odpisových skupin.
        /// </summary>
        byte[] poctyLet = { 3, 5, 10, 20, 30, 50 };
        /// <summary>
        /// Pole pro koeficienty rovnoměrného odpisování definované zákonem dle odpisových skupin.
        /// </summary>
        decimal[] koeficienty = { 40, 22.25m, 10.5m, 5.15m, 3.4m, 2.02m };
        /// <summary>
        /// Pole pro jednotlivé údaje na 1 řádku..
        /// Délka pole = počet sloupců.
        /// </summary>
        string[] zaznam = new string[4];
        /// <summary>
        /// Proměnná představující částku oprávek.
        /// </summary>
        private decimal opravky;
        /// <summary>
        /// Proměnná pro chybu zápisu do souboru.
        /// </summary>
        private bool chybaZapisu = false;
        /// <summary>
        /// Proměnná pro typ odpisů (zrychlené = true, rovnoměrné = false)
        /// </summary>
        private bool typ;
        /// <summary>
        /// List náplň pro výpis v excelu.
        /// </summary>
        List<string> napln = new List<string>();

        /// <summary>
        /// Zobrazí okno, nastaví úvodní hodnoty.
        /// </summary>
        public Odpisovac()
        {
            InitializeComponent();
            porizovaciCenaTextBox.Text = "0";
            DateTime datumCas = DateTime.Now;
            rokPorizeniTextBox.Text = datumCas.Year.ToString();
            odpisovaSkupinacomboBox.SelectedIndex = 0;
            vystupListView.FullRowSelect = true;
        }

        /// <summary>
        /// Metoda kontroluje vstupní údaje a případně spoustí výpočty.
        /// </summary>
        private void vypoctiButton_Click(object sender, EventArgs e)
        {
            //pomocná proměnná (true při zjištěné chybě)
            bool chyba = false;
            typ = zrychleneRadioButton.Checked;
            //kontrola vstupů
            if (!decimal.TryParse(porizovaciCenaTextBox.Text, out cena) | (cena < 2000))
            {
                MessageBox.Show("Neplatná hodnota - Pořizovací cena! Pořizovací cena musí být vyšší než 2 000!", "Zpráva", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                chyba = true;
            }
            if (!int.TryParse(rokPorizeniTextBox.Text, out letopocet) | (letopocet < 1900) | (letopocet > 2100))
            {
                MessageBox.Show("Neplatná hodnota - Rok pořízení! Zadejte hodnotu v rozmezí 1900 - 2100.", "Zpráva", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                chyba = true;
            }
            //spuštění nastavení a výpočtů
            if (!chyba)
            {
                cena = Math.Ceiling(cena);
                zcena = cena;
                vystupListView.Items.Clear();
                int p = odpisovaSkupinacomboBox.SelectedIndex;
                pocetLet = poctyLet[p];
                koeficient = koeficienty[p];
                if (typ)
                    ZrychleneOdpis();
                else
                    RovnomerneOdpis();
            }
        }

        /// <summary>
        /// Metoda pro výpočt zrychlených odpisů.
        /// Volá metodu vypisRadek() pro přídání do vystupListView.
        /// </summary>
        private void ZrychleneOdpis()
        {
            odpis = Math.Ceiling(zcena / pocetLet);
            zcena = zcena - odpis;
            VypisRadek();
            letopocet = letopocet + 1;
            for (int i = 1; i < pocetLet; i++)
            {
                odpis = Math.Ceiling(2 * zcena / (pocetLet + 1 - i));
                zcena = zcena - odpis;
                VypisRadek();
                letopocet = letopocet + 1;
            }
        }

        /// <summary>
        /// Metoda pro výpočet rovnoměrných odpisů.
        /// Volá metodu vypisRadek() pro přídání do vystupListView.
        /// </summary>
        private void RovnomerneOdpis()
        {
            odpis = cena * (100 - (koeficient * (pocetLet - 1))) / 100;
            odpis = Math.Ceiling(odpis);
            zcena = zcena - odpis;
            VypisRadek();
            letopocet = letopocet + 1;
            for (int i = 1; i < pocetLet; i++)
            {
                if (i == pocetLet -1 & zcena < odpis)
                {
                    odpis = zcena;
                    zcena = zcena - odpis;
                    VypisRadek();
                }
                else
                {
                    odpis = cena * koeficient / 100;
                    odpis = Math.Ceiling(odpis);
                    zcena = zcena - odpis;
                    VypisRadek();
                    letopocet = letopocet + 1;
                }
            }
        }


        /// <summary>
        /// Metoda pro vypsání 1 naformátovaného řádku tabulky (vystupListView).
        /// </summary>
        private void VypisRadek()
        {
            opravky = cena - zcena;
            zaznam[0] = letopocet.ToString();
            zaznam[1] = odpis.ToString() + String.Format("{0:c}", " Kč");
            zaznam[2] = zcena.ToString() + String.Format("{0:c}", " Kč");
            zaznam[3] = opravky.ToString() + String.Format("{0:c}", " Kč");
            item = new ListViewItem(zaznam);
            vystupListView.Items.Add(item);
        }

        /// <summary>
        /// Metoda kontroluje, že má co exportovat, a když ano volá metodu Exportuj()
        /// </summary>
        private void exportButton_Click(object sender, EventArgs e)
        {
            if (vystupListView.Items.Count == 0)
                MessageBox.Show("Chybí vstupní data pro vytvoření souboru.", "Zpráva", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
            else
                Exportuj();
        }

        /// <summary>
        /// Metoda pro export údajů z vystupListView do externí souboru (dle údajů z vyvolaného saveFileDialogu)
        /// </summary>
        private void Exportuj()
        {
            napln.Clear();
            int i = 0;;
            string radek;
            saveFileDialog.Filter = "Textové dokumenty (*.txt)|*.txt|Sešit aplikace Excel(*.xlsx)|*.xlsx|Všechny soubory (*.*)|*.*";
            if (saveFileDialog.ShowDialog() == DialogResult.OK)
            {
                foreach (ListViewItem item in vystupListView.Items)
                {
                    if (chybaZapisu)
                        break;
                    item.Selected = true;
                    //nastaveni vystupu
                    radek = "";
                    for (int j = 0; j < zaznam.Length; j++)
                    {

                        zaznam[j] = vystupListView.SelectedItems[i].SubItems[j].Text;
                        radek += zaznam[j].PadRight(20);
                    }

                    if (saveFileDialog.FileName.ToString().Contains("txt"))
                        zapisTXT(radek, i);
                    else if (saveFileDialog.FileName.ToString().Contains("xlsx"))
                        naplnExcel(i);
                    i++;
                }
            }
        }

        /// <summary>
        /// Metoda pro samotný zápis do souboru
        /// </summary>
        /// <param name="radek">Text řádku výstupu</param>
        /// <param name="i">Pořadí řádku - pro vypsání hlavičky.</param>
        private void zapisTXT(string radek, int i)
        {
            try
            {
                if (i == 0)
                {
                    using (StreamWriter sw = new StreamWriter(saveFileDialog.FileName))
                    {
                        if (typ)
                            sw.WriteLine("Zrychlené odpisy");
                        else
                            sw.WriteLine("Rovnoměrné odpisy");

                        sw.WriteLine();
                        sw.WriteLine("Cena pořízení: " + cena.ToString());
                        sw.WriteLine();
                        sw.WriteLine("Rok".PadRight(20) + "Odpis".PadRight(20) + "Zůstatková cena".PadRight(20) + "Oprávky");
                        sw.WriteLine(radek);
                        sw.Flush();
                    }
                }
                else
                {
                    using (StreamWriter sw = new StreamWriter(saveFileDialog.FileName, true))
                    {
                        sw.WriteLine(radek);
                        sw.Flush();
                    }
                }
            }
            catch
            {
                MessageBox.Show("Chyba zápisu do souboru.", "Zpráva", MessageBoxButtons.OK, MessageBoxIcon.Error);
                chybaZapisu = true;
            }
        }


        /// <summary>
        /// Metoda pro naplnění Listu náplň.
        /// Při posledním volání zavolá metodu zapisExcel().
        /// </summary>
        /// <param name="i">prom. počítadlo</param>
        private void naplnExcel(int i)
        {
            for (int j = 0; j < zaznam.Length; j++)
                napln.Add(zaznam[j]);
            if (i == pocetLet - 1)
            {
                zapisExcel();
            }
        }

        /// <summary>
        /// Metoda pro zapsání výstupu do Excelu.
        /// Využívá externí knihovny (todo: přijít na způsob inteligentního/kratšího formátování)
        /// </summary>
        private void zapisExcel()
        {
            FileInfo novySoubor = new FileInfo(saveFileDialog.FileName.ToString());
            try
            {
                if (novySoubor.Exists)
                {
                    novySoubor.Delete();
                    novySoubor = new FileInfo(saveFileDialog.FileName.ToString());
                }
                using (ExcelPackage package = new ExcelPackage(novySoubor))
                {
                    // Vytvoření nového listu
                    ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Odpisy");

                    int m = 0;
                    decimal bunka;

                    //hlavička
                    if (typ)
                        worksheet.Cells[1, 1].Value = "Zrychlené odpisy";
                    else
                        worksheet.Cells[1, 1].Value = "Rovnoměrné odpisy";
                    worksheet.Cells[1, 1].Style.Font.Size += 6;
                    worksheet.Cells[1, 1].Style.VerticalAlignment = ExcelVerticalAlignment.Center;
                    worksheet.Cells[1, 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                    worksheet.Cells[1, 1, 1, 4].Merge = true;
                    worksheet.Cells[3, 1].Value = "Pořizovací cena:";
                    worksheet.Cells[3, 3].Value = cena;
                    worksheet.Cells[3, 3].Style.Numberformat.Format = "#,##0 Kč";
                    worksheet.Cells[3, 1, 3, 2].Merge = true;
                    worksheet.Cells[5, 1].Value = "Rok";
                    worksheet.Cells[5, 2].Value = "Odpis";
                    worksheet.Cells[5, 3].Value = "Zůstková cena";
                    worksheet.Cells[5, 4].Value = "Oprávky";
                    worksheet.Column(1).Width = 8;
                    for (int i = 2; i < zaznam.Length + 1; i++)
                        worksheet.Column(i).Width = 17;

                    worksheet.Cells[1, 1, 5, 4].Style.Font.Bold = true;

                    for (int r = 6; r < pocetLet + 6; r++)
                    {
                        for (int s = 1; s < zaznam.Length + 1; s++)
                        {
                            if (decimal.TryParse(napln[m].Replace(" Kč", ""), out bunka))
                            {
                                worksheet.Cells[r, s].Value = bunka;
                            }
                            else
                                worksheet.Cells[r, s].Value = zaznam[m];
                            m++;
                            if ((r == pocetLet + 5) & (s == zaznam.Length))
                            {
                                worksheet.Cells[5, 1, r, s].Style.Border.Top.Style = ExcelBorderStyle.Thin;
                                worksheet.Cells[5, 1, r, s].Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
                                worksheet.Cells[5, 1, r, s].Style.Border.Left.Style = ExcelBorderStyle.Thin;
                                worksheet.Cells[5, 1, r, s].Style.Border.Right.Style = ExcelBorderStyle.Thin;
                                worksheet.Cells[5, 1, r, s].Style.Border.BorderAround(ExcelBorderStyle.Medium);
                                worksheet.Cells[6, 2, r, s].Style.Numberformat.Format = "#,##0 Kč";
                                worksheet.Cells[5, 1, r, 1].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                                worksheet.Cells[5, 2, 5, s].Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                            }
                        }
                    }
                    package.Save();
                }
            }
            catch
            {
                MessageBox.Show("Chyba zápisu do souboru.", "Zpráva", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }


    }
}
Editováno 18.5.2013 14:51
Odpovědět
18.5.2013 14:50
Neaktivní uživatelský účet
Avatar
Odpovídá na Neaktivní uživatel
Drahomír Hanák:18.5.2013 14:55

Pěkné, ale mohl bys to rozdělit do víc tříd. Takhle je to strašně přeplácané a nepřehledné.

 
Nahoru Odpovědět
18.5.2013 14:55
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Neaktivní uživatel
David Hartinger:18.5.2013 15:01

Docela hezká třída, máš tam pár metod s malým písmenem :P Co je ExcelWorksheet, něco 3. strany nebo od MS?

Nahoru Odpovědět
18.5.2013 15:01
New kid back on the block with a R.I.P
Avatar
Neaktivní uživatel:18.5.2013 15:29

Díky za názory:)

2Drahoš: ok - v tomhle případě mi přijde nejlepší dát do vlastní třídy metody týkající se exportu (do budoucna, v závislosti na realizaci ostatních plánů asi i samotné kalkulace a třídu pak nechat jen čistě pro zadávání/zobra­zování)

2sdraco: ty názvy metod sem nějak přehlídnul ;( ExcelWorksheet je 3. strany

Nahoru Odpovědět
18.5.2013 15:29
Neaktivní uživatelský účet
Avatar
Neaktivní uživatel:23.5.2013 10:37

Pracuji na návrhu další verze a řešim problém výhodnosti načítání dat z databáze / jejich dopočítání (počítám s tím, že se na začátku načte seznam majetku* z databáze na úvodní obrazovku s jeho seznamem, a pak bude možné rozkliknout na přehled/přidá­ní/úpravu odpisů daného majetku):

  1. možnost: veškěrá (případně skoro veškerá) data včetně těch o odpisech by se načítala z databáze
  2. možnost: data o odpisech (do přehledu odpisů k danému majetku) by se pokaždé dopočítala (víceméně dle původního návrhu, viz první post)

Uvažuji o rozdílu běhu rychlosti aplikace v případě několika položek majetku (kde rozdíl bude zanedbatelný) vs několik tisíc kusů majetku (a tím pádem např. desítky tisíc řádků odpisů vyhledávaných dle ID majetku). Rád bych si oveřil/vyvrátil svoji hypotézu, a proto bych poprosil, jestli by se někdo zkušenější nemohl vyjádřit.

*pozn.: počítám s přednastaveným omezením na xy položek majetku + filtry/vyhledávání, aby úvodní načítání při většího množství položek majetku v databázi netrvalo příliš dlouho

Editováno 23.5.2013 10:38
Nahoru Odpovědět
23.5.2013 10:37
Neaktivní uživatelský účet
Avatar
Neaktivní uživatel:24.5.2013 22:29

tak nic, vyřešeno + nebylo by možné alespoň do inkubátoru přidat možnost editace?

Nahoru Odpovědět
24.5.2013 22:29
Neaktivní uživatelský účet
Avatar
David Hartinger
Vlastník
Avatar
Odpovídá na Neaktivní uživatel
David Hartinger:25.5.2013 9:29

Inkubátor je jen pro oznámení, pokud chceš něco prezentovat vážněji, přidej to jako program :)

Nahoru Odpovědět
25.5.2013 9:29
New kid back on the block with a R.I.P
Avatar
Odpovídá na David Hartinger
Neaktivní uživatel:25.5.2013 9:36

OK, díky za info.

Nahoru Odpovědět
25.5.2013 9:36
Neaktivní uživatelský účet
Avatar
Kit
Tvůrce
Avatar
Odpovídá na Neaktivní uživatel
Kit:25.5.2013 10:42

Pokud chceš editovat soubor i po vložení, používej "Vložení dlouhého zdrojáku" pod okénkem příspěvku.

Nahoru Odpovědět
25.5.2013 10:42
Vlastnosti objektů by neměly být veřejné. A to ani prostřednictvím getterů/setterů.
Avatar
Neaktivní uživatel:25.5.2013 12:27

Díky za tip, vyzkouším u dalšího projektu

Editováno 25.5.2013 12:28
Nahoru Odpovědět
25.5.2013 12:27
Neaktivní uživatelský účet
Avatar
Neaktivní uživatel:8.6.2013 17:12

Zdravím,

tak po nějaké době sem dávám další trochu funkčnější verzi Daňových odpisů:

ke stažení:
http://uloz.to/…o2013v01-zip
podstatné části zdrojového kódu:
http://www.itnetwork.cz/dev-lighter/108

Hlavní změny:

  • dočasně odebrána možnost exportu
  • přidána správa majetku - Přehled majetku, Přidání majetku (databáze majetku a odpisů) a další související/pomocné třídy (více vrstev)
  • překopána třída Odpisovač

poznámky k ovládání:

  • do odpisovače (pro přehled a kalkulaci odpisů určité položky majetku) se dostanete rozkliknutím položky majetku v přehledu majetku.
  • pro řazení položek majetku klik na záhlaví sloupce.

V plánu:

  • možnost úprav a mazání vybraných a všech položek majetku (a zároveň příslušných odpisů)
  • Export/Import do/z Excelu (excelovský dokument by sloužil jako záloha + možnost přenositelnosti mezi PC)
  • přidání dalších možností pro odpisování
  • menu, zapracovat na vzhledu
  • další drobné změny, úpravy a vylepšení kódu

Dotazy:

  • Ve třídě Filtrovac metoda Zobraz - zatím jsem nepřišlel za pomocí Linq to SQL na lepší řešení - nevěděl by prosim někdo, jak to dát jednoho dotazu, respektive jestli je to možné (ideálně aby nedošlo zároveň ke zpomalení běhu dotazu)?
  • Uživatelské rozhraní - sice jsem už zvažoval několik možností, ale zatím nemám konkrétní představu, takže bych poprosil o vaše návrhy.
  • Nápady, názory, možnosti vylepšení, co vás napadne.
Nahoru Odpovědět
8.6.2013 17:12
Neaktivní uživatelský účet
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 11 zpráv z 11.