Postać Docelowa Faktury

Po dwutygodniowym rejsie po Mazurach, czas wrócić do pracy nad projektem. Aby skończyć warstwę logiki biznesowej, muszę jeszcze tylko stworzyć klasę, która zajmie się zamianą przyczajonej w bazie danych, zdigitalizowanej do cna postaci faktury w nie mniej zdigitalizowaną, ale niepomiernie bardziej czytelną dla użytkownika programu, postać dokumentu PDF. Użyję w tym celu biblioteki PdfSharp.

BHP z ostrym narzędziem
Tworzenie dokumentów PDF przy pomocy PdfSharp nie jest trudne. Przygotowanie nowego dokumentu to tylko kilka linijek:

PdfDocument document = new PdfDocument(); // stworzenie nowego dokumentu
PdfPage page = document.AddPage(); // stworzenie nowej strony dokumentu
XGraphics graphics = XGraphics.FromPdfPage(page); // stworzenie obiektu odpowiedzialnego za wygląd strony

Obiektem odpowiedzialnym za umieszczanie grafiki i treści na stronach dokumentu jest instancja klasy XGraphics. Na wygląd faktury będą się składać wyłącznie prostokąty i tekst, dlatego przedstawię sposób generowania tylko tych elementów.
Za tworzenie prostokątów odpowiada metoda DrawRectangle. Przykładowo, kod:

XPen pen = new XPen(XColors.Black, 1); // obramowanie prostokąta
XBrush brush = XBrushes.Red; // wypełnienie prostokąta
XRect rect = new XRect(0, 0, 60, 20); // położenie i wymiary prostokąta (x, y, szerokość, wysokość)
graphics.DrawRectangle(pen, brush, rect); // narysowanie prostokąta

narysuje w lewym górnym rogu strony czerwony prostokąt z czarnym obramowaniem.
Umieszczaniem na stronie tekstu zajmuje się metoda DrawString. I tak, kod:

XFont font = new XFont("Arial", 10, XFontStyle.Bold); // krój, rozmiar i styl czcionki
graphics.DrawString("Poufne", font, XBrushes.Black, rect, XStringFormats.Center); // dodanie czarnego napisu w środku stworzonego wcześniej prostokąta

sprawi, że nasz dokument, niezależnie od dalszej treści, będzie mógł być wykorzystany jako rekwizyt w dowolnym filmie szpiegowskim.

Przyda mi się także metoda MeasureString, zwracająca rozmiar napisu pisanego zadaną czcionką:

XSize size = graphics.MeasureString("<napis do zmierzenia>", czcionka);

Zapisanie dokumentu na dysku to nic więcej, niż napisanie:

document.Save("<nazwa pliku>");

Te metody (i ich przeciążenia) w zupełności wystarczą do wystawienia faktury VAT.

Very Arduous Task
Przepisy określają informacje, jakie muszą się znaleźć na fakturze:

  • nazwy i adresy sprzedawcy i nabywcy oraz ich numery NIP
  • datę dokonania sprzedaży oraz datę wystawienia dokumentu
  • napis Faktura VAT oraz numer kolejny faktury
  • nazwę towaru lub usługi (przedmiotu transakcji)
  • jednostkę miary i ilość sprzedanych towarów lub rodzaj wykonanych usług
  • cenę jednostkową towaru lub usługi bez kwoty podatku (cenę jednostkową netto)
  • wartość towarów lub wykonanych usług, których dotyczy sprzedaż, bez kwoty podatku (wartość sprzedaży netto)
  • stawki podatku
  • sumę wartości sprzedaży netto towarów lub wykonanych usług z podziałem na poszczególne stawki podatku, zwolnionych z podatku oraz niepodlegających opodatkowaniu
  • kwotę podatku od sumy wartości sprzedaży netto, z podziałem na kwoty dotyczące poszczególnych stawek podatku
  • wartość sprzedaży towarów lub wykonanych usług wraz z kwotą podatku (wartość sprzedaży brutto), z podziałem na kwoty dotyczące poszczególnych stawek podatku, zwolnionych z podatku lub niepodlegających opodatkowaniu
  • kwotę należności ogółem wraz z należnym podatkiem (brutto), wyrażoną cyframi i słownie
  • źródło: wikipedia

    Nie opisują jednak, jak dokładnie faktury mają wyglądać. Te wystawiane za pomocą InvoiceInvoker będą podobne do tworzonych przez program inFakt (jak już wcześniej wspominałem, zamierzam się czasem na nim wzorować), co, mam nadzieję, nie jest wykroczeniem. Po wielu godzinach tworzenia prostokątów, zmieniania ich rozmiarów i przesuwania o piksel, a także wypełniania tekstem o żmudnie dopasowywanych czcionkach, uzyskałem kod generujący akceptowalnie wyglądające dokumenty. Oto wyniki testów:
    [uwaga: arytmetyka nie była przedmiotem testów, dlatego nie należy szukać sensu w liczbach widniejących na fakturach]
    test_CreatesNormalInvoice
    test_HandlesVeryLongStrings
    test_SplitsProducts
    test_SplitsGeneralAmountsInfo
    test_SplitsPaymentInfo
    test_SplitsRemarks
    test_SplitsSignatures.

    Kodu klasy nie zamieszczam z oczywistego powodu: jest długi i nudny. Wytrwałym śmiałkom podpowiem jednak, że można go znaleźć tutaj. Wszystkim, którzy szukają sposobu na przeistoczenie kodu w dokument PDF, mogę natomiast polecić dokładniejsze zapoznanie się z PdfSharp.
    Wygląda na to, że warstwa logiki biznesowej jest już ukończona. Wkraczam więc na niepewny grunt: ASP.NET MVC, którego opanowanie jest jednym z głównych celów mojego udziału w konkursie. Stay tuned!