Wypowiedzi
-
Proponuję mPDF:
http://www.mpdf1.com/mpdf/index.php?page=Features
http://mpdf1.com/manual/index.php
Używam z powodzeniem od lat. Można tworzyć pdf analogicznie jak w fpdf ale dodatkowo np:
1. Tworzenie plików pdf z kodu html
2. CSS
3. Relatywne/absolutne pozycjonowanie tagów
4. Zaawansowana obsługa nagłówków i stopek (storna piwersza, prawe, lewe).
5. Możliwość zwrócenia do przeglądarki, zapisania do pliku itp.
6. Bogata dokumentacja z przykładami użycia
Bardzo ładnie generuje wszelakiego rodzaju dokumenty (tutaj przykład użycie) i darmowy. -
Skromnie podrzucam pomysł z wdrożeniem replikacji. Dane będą powielane na oddzielnym serwerze na bieżąco i wtedy kopie nocne można by robić na okrągło z serwera slave. Niestety w MSSQL się nie specjalizuję ale zakładam, że mechanizm replikacji posiada. Przy replikacji pojawiają się oczywiście inne zagadnienia i problemy ale rozwiązanie powinno pomóc utrzymać bazę na ruchu w momencie tworzenia kopii i nie obciąży serwera master.
-
Ok teraz chyba rozumiem co chcesz zrobić. Dobrych wieści nie mam. Ustawienie przez requestFocus() może nie ustawiać prawidłowo focusu. Z tego co wiem nadawanie focusa jest zależne od używanego systemu operacyjnego, na którym rusza silnik java. Zarządzanie JFrame podlega zasadom używanego menagera okien w danym systemie. Prościej mówiąc w systemie może być okno o takim priorytecie wyświetlania, że menager okien nie pozwoli zrobić operacji focus na oknie które chcemy. Mogę się oczywiście mylić ale nic innego nie przychodzi mi do głowy. Proponuję przed wywołaniem metody requestFocus() użyć jeszcze na wszelki wypadek metody toFront(). Myślę, że to zminimalizuje problem ale raczej go nie usunie.Ten post został edytowany przez Autora dnia 20.06.15 o godzinie 22:02
-
Nie wiem jak masz napisane wątki i dialog dla użytkownika. Jeżeli jednak wyświetlenie dialogu, jakikolwiek by on nie był, powoduje zatrzymanie działania całej reszty to raczej nie masz dobrze zrobionych wątków. Podaję przykład działania JFrame do którego wpisywane są treści z trzech niezależnych wątków. Wątki działają w tle a przekazanie danych odbywa się przez wyzwolenie Event oraz przez wprowadzenie odpowiedniego interface typu EventListener. Kod uruchamiany i zgodny z JAVA 7 (w 8 można poprawić przejrzystość kodu przy dodawaniu listenera przez zastosowanie struktury ze znakiem/znacznikiem lambda).
Tutaj link bo tak się rozpisałem, że tak długiej wiadomości GL nie chce przetworzyć...
SRC -
Masz:
1. Otwierasz pierwszą pętlę while aby iterować wiersze
2. Dodajesz imputy
3. Zamykasz pierwszą pętlę while
4. Otwierasz drugą pętlę while aby zbudować select
5. Zamykasz drugą pętlę while
Powinieneś mieć:
1. Przenieść kod drugiego while do pierwszego czyli robisz kolejno pkt według kolejności: 1, 2, 4, 5, 3
A tak na marginesie:
Po wykonaniu pkt tak aby pierwszy while był w drugim niepotrzebnie wykonujesz drugiego while w ilości liczba pętli while * liczba wierszy. Zrobiłbym generowanie tagów <option> raz i zapamiętałbym w zmiennej i potem dla każdego wiersza po prostu wyświetliłbym listę zamiast generować ją przy każdym obrocie pierwszego while.
Zauważyłem też, że otwierasz tag form ale go nie zamykasz. Czy na pewno każdy wiersz ma być oddzielną formą?
Jeżeli przy każdym wierszu mają być jakieś polecenia do zrobienia to lepiej było by załatwić to linkiem przekazując get'em tylko id wiersza oraz akcję jaka ma zostać wykonana po przyciśnięciu linku. Można też tak jak się to teraz ciągle robi po przyciśnięciu przycisku wykonać funkcję za pomocą ajax'a :)Ten post został edytowany przez Autora dnia 18.06.15 o godzinie 22:19 -
Jeżeli to MySQL to uważam, że w podzapytaniu lepiej użyć zamiast
to_char(date, 'YYYY') = to_char(sysdate, 'YYYY')
formyyear(date) = year(sysdate)
A po co pisać rok w nazwie kolumny skoro zapytanie zwraca zawsze dla bieżącego roku systemowego? Nie lepiej nazwać kolumnę np "ten_rok"?
Jeżeli jednak faktycznie dla danych z kilku lat to proponuję najpierw podliczyć quantiy z tabeli zapas z podziałem na part_no (zakładam, że tabela zapas przechowuje ilości dla różnych part_no) oraz na rokSELECT sum(quantity) AS suma, rok, part_no FROM (
a następnie zrobić join z tabelą z informacjami typu part_no, description
SELECT quantity, year(date), part_no AS rok FROM zapas
) AS ret GROUP BY rok, part_noSELECT x.part_no, x.description, COALESCE(s.suma, 0) AS suma, s.rok
i potem tak jak pisał Paweł - odwracamy tabelę np PIVOT
FROM jakas_tabela x
LEFT JOIN (
SELECT sum(quantity) AS suma, rok, part_no FROM (
SELECT quantity, year(date), part_no AS rok FROM zapas
) AS ret GROUP BY rok, part_no
) AS sumy s ON x.part_no = s.part_no
Zakładam szereg pomyłek ze względu na brak znajomości struktury bazy danych :) -
Ja tylko nie rozumiem dlaczego się uparłeś na wrzucanie na ftp i potem z udziału na serwerze commit do repozytorium.
W dużym uproszczeniu zrobił bym tak:
1. Wykonaj sobie lokalnie na komputerze środowisko deweloperskie (Serwer www, baza danych i inne).
2. Stwórz projekt w dowolnym narzędziu do kontroli wersji i wrzuć tam wykonane przez siebie pliki projektu. Pliki w zależności od systemu kontroli wersji wrzucasz do głównej gałęzi (np trunk w SVN albo master w GIT). Te pliki to twoja wersja produkcyjna.
3. W systemie kontroli wersji stwórz sobie branch dla potrzeb deweloperskich (np o nazwie dev).
4. Na swoim komputerze (przygotowanym wg pkt 1) zrób sobie checkout branch'a dev do takiego katalogu żeby aplikacja działała lokalnym serwerze www. Wykonaj konfigurację (jeżeli aplikacja takową posiada) i oznacz pliki w systemie kontroli wersji tak aby nie zostały przypadkowo przesłane.
Teraz masz podstawę do robienia aktualizacji produkcji oraz miejsce na rozwój i testowanie. Jeżeli wprowadzasz zmianę w kodzie do zawsze robisz to na branch'u "dev". Jeżeli uważasz że twoje zmiany można przesłać na produkcję to synchronizujesz branch dev z głównym i już masz zmiany które można wrzucać na produkcję.
Teraz na twój serwer nie przerzucasz plików przez ftp. Tworzysz tam sobie także kopię roboczą z systemu kontroli wersji. Jak chcesz przesłać zmiany na serwer to na swoim kompie wykonujesz commit a na serwerze zdalnym na kopii roboczej wykonujesz update.
5. Robię kopię roboczą (checkout) na serwerze zdalnym w miejscu dotychczaowego projektu.
Identycznie możesz postąpić z serwerem zdalnym testowym jak i z produkcyjnym. Takie rozwiązanie daje Ci możliwość automatycznego aktualizowania wersji. Np możesz ustawić, że serwer testowy ma aktualizować sobie kod np co 15 min albo raz na godzinę (update kopii roboczej jako skrypt w crontab). Chcesz oddać coś do testów to robisz commit a za godzinkę przesyłasz info do testerów, że można potestować na serwerze testowym.
6. Automatyzacja aktualizacji kodu na serwerach (crontab).
Taki rozwiązanie jest o tyle fajne, że możesz oddać kawałek aplikacji na testówce do przeklikania a sam na swoim kompie dorabiasz kolejne funkcjonalności. Zaznaczam jeszcze raz, że ten model pracy w bardzo dużym uproszczeniu... -
Każda z twoich klas może zawierać konstruktor który przyjmie jako parametr model danych
class Klasa {
i możesz wewnątrz klasy pracować na modelu danych
private final ModelDanych MODEL;
public Klasa(ModelDanych model) {
MODEL = model;
}
}
Nie rozumiem tylko tego, że masz jedną listę i potrzebujesz kilka klas na jej obsługę. Wykonaj jedną klasę w której zaimplementujesz metody dodawania wyświetlania i edycji listy. Inicjujesz wtedy zawsze jeden obiekt danej klasy i masz wszystkie niezbędne metody.class Klasa {
Możesz również zrobić klasę z metodami które za parametr przyjmą twój model danych, zrobią coś na nim i zwrócą zmieniony.
private final ModelDanych MODEL;
public Klasa(ModelDanych model) {
MODEL = model;
}
/**
* Wyświetlanie danych w JTable.
*/
public void Wyswietl(JTable table) {
if (table == null) return;
}
/**
* Dodawanie danych do modelu.
* @var values
*/
public void Dodaj(Object..values] {
if (values.length == 0) return;
}
/**
* Edycja danych.
* @var identyfier Identyfikator wiersza w modelu
* @var values Tablica z nowe dane
*/
public void Edytuj(Object identyfier, Object..values) {
if (identyfier == null || values.length == 0) reutrn;
}
/**
* Usuwanie danych
* @var identyfier Identyfikator wiersza do usunięcia
*/
public void Usun(Object identyfier) {
if (identyfier == null) return;
}
} -
To o czym piszesz to według mnie rozwiązanie na trzy tabele a nie na dwie. Obrazowo (PostreSQL):
CREATE TABLE platnosci(
Masz tabele z płatnościami, wpłatami oraz pamiętającą parowania i kwoty parowań. Zakładam tu, że parowanie płatności z wpłatą może nastąpić tylko raz oraz do jednej płatności może być wiele parowań a jedna wpłata może być rozbita na kilka płatności.
id_platnosci SERIAL PRIMARY KEY,
id_dokumentu_kasowego INT,
kwota_platnosci FLOAT
);
CREATE TABLE wplaty(
id_wplaty SERIAL PRIMARY KEY,
kwota_wplaty FLOAT
);
CREATE TABLE platnosci_wplaty(
id_platnosci INT,
id_wplaty INT,
kwota_parowania FLOAT,
PRIMARY KEY (id_platnosci, id_wplaty)
FOREIGN KEY (id_platnosci) REFERENCES platnosci (id_platnosci)
MATCH SIMPLE ON UPDATE CASCADE ON DELETE CASCADE,
FOREIGN KEY (id_wplaty) REFRENCES wplaty(id_wplaty)
MATCH SIMPLE ON UPDATE CASCADE ON DELETE CASCADE
);
Teraz wypadałoby założyć trigger on insert oraz update na tabeli wpłaty, który uruchomi funkcję według algorytmu:
1. Szukaj wpłat które nie zostały w całości rozłożone na płatności i oblicz dla każdej wpłaty kwotę do rozbicia
2. Szukaj płatności które nie zostały w całości zapłacone
3. Jeżeli nowa wpłata (insert)
a) Dodaj kwoty parowania dla płatności niezapłaconych posortowanych po terminie płatności począwszy od najstarszej.
b) Powtarzaj 3a tak długo aż kwota wpłaty będzie 0 albo kwota płatności do zapłaty będzie 0 a następnie zakończ działanie
4. Jeżeli zmiana istniejącej wpłaty (update) i zmiana kwoty wpłaty na większą
a) Wyszukaj wszystkie płatności do których są parowania z wpłaty a następnie sprawdź czy te płatności są do zapłaty.
b) Jeżeli są parowania i dla tych parowań są płatności jeszcze do zapłaty to skasuj te parowania i wykonaj nowe według pkt 3 (ale tylko dla płatności sparowanych ze zmienianą wpłatą)
c) Jeżeli są parowania i dla tych parowań nie ma płatności do zapłaty to wykonaj nowe parowania według pkt3
5. Jeżeli zmiana istniejącej wpłaty (update) i zmiana kwoty wpłaty na mniejszą
a) Wyszukaj parowania dla zmienianej wpłaty a następnie zmniejszaj kwoty parowań dla płatności z najpóźniejszym terminem płatności.
b) Jeżeli kwota zmniejszanego parowania jest 0 to usuń parowanie.
Analogicznie trzeba zrobić na tabeli płatności bo każda zmiana płatności może spowodować nadpłatę lub niedopłatę.
Trochę skomplikowane ale wyciąganie dokumentów kasowych oraz wyliczanie do nich kwot do zapłaty/nadpłaty albo jest wtedy proste. Tak samo obliczanie salda czy sprawdzanie niezgodności. -
A dlaczego ogóle wyszukiwanie po nazwach tematów? Znaczy się, że przy każdym poście dla danego tematu przechowujesz jego tytuł i po tym zwracasz listę postów? A co zrobisz jeżeli na przestrzeni czasu pojawią się dwa tematy o podanej takiej samej nazwie? A co zrobisz jeżeli temat wątku zostanie zmieniony bo np poprawiono literówkę? Poprawiasz wszystkie posty?
Może lepiej zrobić tabelę z listą tematów (wątków) gdzie każdy temat ma swoje id a następnie w tabeli z postami zrobić klucz obcy id_watku do tabeli z tematami? Wtedy w request przekazujesz id wątku i wyciągasz wszystko po kolumnach typu int. Zawsze ci zwróci poprawnie a z porównywaniem stringów to nie jest dobre rozwiązanie. Jak pisał przedmówca string stringowi nie równy chociażby o białe znaki na które użytkownicy kompletnie nie zwracają uwagi.
User: "Przecież to jest ten sam tekst ... ja widzę na ekranie dobrze" :) -
Komplet dokumentacji dla projektów u mnie nie zawsze ale przy ważniejszych projektach składa się:
1. Założenia merytoryczne, analiza opłacalności oraz potrzeby. Wstępny zarys funkcjonalności (opracowuje biznes + analityk).
2. Projekt funkcjonalny, techniczny. Zawiera merytoryczny opis funkcjonalności do wykonania (opracowuje biznes + analityk) oraz techniczny opis funkcjonalności np. przypadki użycia, przepływ, informacje o przechowywanych danych w db (opracowuje analityk + ewentualnie informatyk programista).
3. Dokumentacja techniczna. Zawiera informacje dotyczące kodu i zaimplementowanych funkcjonalności. Dokumentacja tworzona w popularnym dla danej technologii doku (np. javadoc, phpdoc). Tworzona przez programistę i z reguły generowana do postaci HTML.
4. Instrukcja instalacji gotowego narzędzia (powinien tworzyć analityk albo wdrożeniowiec ale u nas kończy się na testerze albo programiście ...).
5. Instrukcja użytkownika (powinien tworzyć analityk albo wdrożeniowiec ale jest tak jak w poprzednim punkcie).
Dodatkowo jeszcze może być generowany changelog z komentarzy przy aktualizacji SVN lub innego popularnego repozytorium i udostępniany wraz z wyprodukowaną aplikacją.
Ostatni projekt był odświeżeniem oprogramowania napisanego z 6-7 lat temu i tu zrobiłem instrukcję użytkownika w postaci zestawu screencast'ów (ok 1h nagrań). Muszę powiedzieć, że wśród użytkowników końcowych przyjęło się lepiej niż instrukcja papierowa która również została zaktualizowana. -
Kolego nie dziw się, że masz takie odpowiedzi a nie inne. Żaden ceniący się programista nie będzie pracował nie wiadomo nad czym nie wiadomo za ile i nie wiadomo kiedy płatne. Nie określiłeś też formy współpracy. Masz na myśli, że jak będę chciał z tobą współpracować to ja ci oddam swój czas a ty mi oddasz udziały z ewentualnie nie wiadomo jakiego pomysłu? Hmm... mam mieć mnóstwo czasu? ale ile czasu? tydzień, miesiąc? rok? Pytam po przez ten czas trzeba płacić rachunki i mieć co do gara włożyć...
Najgorsze jednak jest to, że traktujesz ewentualnego zainteresowanego z góry i pretecha po co odpisał. Ja się pytam po co ty pisałeś? Jak praca charytatywna to się udam do MOPR'u.
Eh... zły dzień dzisiaj -
Szymon G.:
... a jedynym sposobem uniknięcia problemu od strony programisty jest albo zrobienie programu liczącego na wszelkie możliwe sposoby i niechże sobie użytkownik wybierze odpowiednią wersję w konfiguracji (jakby co, to bedzie jego wina) albo też niech klient na piśmie poda jak to ma liczyć i tak mu zrobić (i wtedy też będzie to jego wina).
Co racja to racja.
Zawsze na wszelki wypadek warto sobie zrobić dupochron :)
Przecież nie ma złych programów. Są tylko źli użytkownicy :) -
Ja może i też jestem troll'em jeżeli chodzi o VAT. Z tego co kojarzę to ustawa określa trzy sposoby naliczania podatku:
1. Od kwoty netto
2. Od kwoty brutto
3. Od kwot za pojedyncze towary i usługi
a przedsiębiorca wystawiający fakturę ma do wyboru jak będzie obliczał VAT. Najważniejsze jest aby kwota podatku znalazła się na dokumentach kasowych i fakturowych. Któryś z panów słusznie zauważył, że ważne jest aby w powiązanych ze sobą dokumentach używać takiego samego sposobu obliczania tej jakże kontrowersyjnej kwoty (wiadomy problem z różnicami na paragonie i fv do niego).
Oznacza to, że takie patrzenie na paragony niczego nie rozwiązuje bo market A może obliczać VAT innym sposobem niż market B.
W sumie jedynym sposobem na uniknięcie problemów jest przyjęcie w całym przedsiębiorstwie takiego samego sposobu obliczania kwoty podatku. -
Kolego drogi studencie... fajnie, że kombinujesz i chcesz się uczyć. Wkleiłeś dwa skrypty (w komentarzach są różni autorzy) i raczej nie sądzę aby były twoje. Jak weźmiesz kod kolegi to go nie zrozumiesz i jakiekolwiek zmiany jakie wykonasz na pewno w niczym nie pomogą. Dodatkowo powielasz czyjeś błędy...
Załóż sobie nowe pliki i przepisuj linia po linii. Sam zobaczysz błędy:
1. Wiele połączeń z bazą danych jak tu kolega pisał.
2. Używasz zmiennych które ogóle nie są zainicjowane (np. $ext w zapytaniu SQL)
3. Pętla while przy jednorazowym zapytaniu do bazy? po co? nie lepiej$result = mysql_query(...);
... W "if" sprawdzasz dwa razy to samo np.
$wierszy = mysql_num_rows($result);
if ($wierszy > 0) {
// Token istnieje
} else {
// Token nie istnieje
}if (empty($image)) { ... }
A nie uczyli?
if (!empty($image)) { ... }if (empty($image)) { ... } else { ... }
n. I tak jeszcze więcej... (SQL Injection) bo za pomocą przekazanego w taki sposób rozszerzenia pliku do zapytania SQL kładę bazę danych w parę minut. -
Zapraszam do biura (bud GG pok 38). Masz w profilu napisane "Poznań". Możemy looknąć, może uda się problem rozwiązać.
-
Lol. Dowolność nazw zmiennych/obiektów polega... na ich dowolności...
-
Dobrze masz to zrobione. Zamianę modelu możesz wpisać w konstruktorze:
List<Samochody> samochody = new ArrayList<>();
Możesz również zrobić metodę która zwróci ModelSamochody:
Samochody samochod = new Samochody();
samochod.setMarka("Seat");
samochod.setModel("Ibiza");
samochody.add(samochod);
ModelSamochody model = new ModelSamochody(samochody, new String[] {
"Marka", "Model", "Rocznik", "Cena"
});
tabela.setModel(model);private ModelSamochody prepareModel() {
Potem w NB w graficznym edytorze klikasz na tabele, we właściwościach/opcjach szukasz "model". Potem otwierasz model tymi [...] i wybierasz w "Set tabela's model property using:" opcję "Custom code" potem w jedynym tam polu piszesz nazwę funkcji. W tym wypadku prepareModel().
List<Samochody> samochody = new ArrayList<>();
ModelSamochody model = new ModelSamochody(samochody, new String[] {
"Marka", "Model", "Rocznik", "Cena"
});
}
Tutaj masz screencast ... działa. <= Zapomniałem wyłączyć dźwięk. W tle dźwięki z akurat lecącego filmu :)Ten post został edytowany przez Autora dnia 02.03.15 o godzinie 21:49 -
Jak dla mnie to zakombinowałeś trochę. NIe potrzebujesz tematu robić iteracyjnie. Ja bym sobie csv wczytał do tymczasowej tabeli i przed wykonaniem aktualizacji sprawdziłbym sobie select csv left join polisy on csv.numer = polisy.numer where polisy.id is null. Jak znajdzie rekordy z csv bez przyporządkowanej polisy to zwracam błąd i mam dokładnie które wiersze ... ergo nie wykonuję żadnej aktualizacji.
Jak wszystkie wiersze z csv mają dopasowaną polisę to robię sobie update tabela set ... join where.
1. Wczytujesz csv
2. Select ze sprawdzeniem po numerach polis
3. Update aktualizujący lub zwracam błąd wraz z listą błędnych wpisów z csv -
Szymon ujął w wypowiedzi cały konkret. Ja się rozpisałem ale skracam.
Musisz niestety wymusić komplet informacji. "Z grubsza" zawsze potem znajdą jakiś przypadek do którego grubsze podejście nie będzie pasowało.
Jak biznes sam nie wie co chce lub nie czuje tematu to powinien pomiędzy biznesem a tobą znaleźć się analityk. Osoba z wiedzą merytoryczną znająca przepisy i zasady rachunkowości ale mająca na tyle techniczne podejście, że będzie umiała przełożyć to na opis dla informatyka.
Bez analityka i decyzji biznesowych się kolego nie obejdzie. Jak zrobisz jak uważasz to zrobisz sobie niekończącą się opowieść. A jak już jakiś model zadziała to po jakimś czasie nie będzie można tego odkręcić i temat błędów w pieniądzach będzie się ciągnął latami. Znam to z autopsji...
Bardzo mi się spodobało stwierdzenie, że programiści mogą zaimplementować cokolwiek. Jak nie będzie konkretu merytorycznego to możesz zaimplementować nawet "cuda na kiju" - też będzie dobrze. Jak każą mimo wszystko implementować bez podawania szczegółów to faktycznie pomyśl o zmianie pracy bo na końcu będziesz koziołek ofiarny.