/************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2020 Melin Software HB This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Melin Software HB - software@melin.nu - www.melin.nu Eksoppsvägen 16, SE-75646 UPPSALA, Sweden ************************************************************************/ // oClub.cpp: implementation of the oClub class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "oClub.h" #include "meos_util.h" #include "oEvent.h" #include "gdioutput.h" #include "gdifonts.h" #include "RunnerDB.h" #include #include "Table.h" #include "localizer.h" #include "pdfwriter.h" #include "HTMLWriter.h" #include "intkeymapimpl.hpp" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// oClub::oClub(oEvent *poe): oBase(poe) { getDI().initData(); Id=oe->getFreeClubId(); } oClub::oClub(oEvent *poe, int id): oBase(poe) { getDI().initData(); Id=id; if (id != cVacantId && id != cNoClubId) oe->qFreeClubId = max(id, oe->qFreeClubId); } oClub::~oClub(){ } wstring oClub::getInfo() const { return L"Club: " + name; } bool oClub::write(xmlparser &xml) { if (Removed) return true; xml.startTag("Club"); xml.write("Id", Id); xml.write("Updated", Modified.getStamp()); xml.write("Name", name); for (size_t k=0;kis("Id")){ Id=it->getInt(); } else if (it->is("Name")){ internalSetName(it->getw()); } else if (it->is("oData")){ getDI().set(*it); } else if (it->is("Updated")){ Modified.setStamp(it->getRaw()); } else if (it->is("AltName")) { altNames.push_back(it->getw()); } } } void oClub::internalSetName(const wstring &n) { if (name != n) { name = n; const wchar_t *bf = name.c_str(); int len = name.length(); int ix = -1; for (int k=0;k <= len-9; k++) { if (bf[k] == 'S') { if (wcscmp(bf+k, L"Skid o OK")==0) { ix = k; break; } if (wcscmp(bf+k, L"Skid o OL")==0) { ix = k; break; } } } if (ix >= 0) { tPrettyName = name; if (wcscmp(bf+ix, L"Skid o OK")==0) tPrettyName.replace(ix, 9, L"SOK", 3); else if (wcscmp(bf+ix, L"Skid o OL")==0) tPrettyName.replace(ix, 9, L"SOL", 3); } } } void oClub::setName(const wstring &n) { if (n != name) { internalSetName(n); updateChanged(); } } oDataContainer &oClub::getDataBuffers(pvoid &data, pvoid &olddata, pvectorstr &strData) const { data = (pvoid)oData; olddata = (pvoid)oDataOld; strData = 0; return *oe->oClubData; } pClub oEvent::getClub(int Id) const { if (Id<=0) return 0; pClub value; if (clubIdIndex.lookup(Id, value)) return value; return 0; } pClub oEvent::getClub(const wstring &pname) const { oClubList::const_iterator it; for (it=Clubs.begin(); it != Clubs.end(); ++it) if (it->name==pname) return pClub(&*it); return 0; } pClub oEvent::getClubCreate(int Id, const wstring &createName) { if (Id > 0) { //map::iterator mit=clubIdIndex.find(Id); //if (mit!=clubIdIndex.end()) { pClub value; if (clubIdIndex.lookup(Id, value)) { if (!trim(createName).empty() && _wcsicmp(value->getName().c_str(), trim(createName).c_str())!=0) Id = 0; //Bad, used Id. if (trim(createName).empty() || Id>0) return value; } } if (createName.empty()) { int id = oe->getVacantClub(true); //Not found. Auto add... return getClubCreate(id, lang.tl("Klubblös")); } else { oClubList::iterator it; wstring tname = trim(createName); //Maybe club exist under different ID for (it=Clubs.begin(); it != Clubs.end(); ++it) if (_wcsicmp(it->name.c_str(), tname.c_str())==0) return &*it; //Else, create club. return addClub(tname, Id); } } pClub oEvent::addClub(const wstring &pname, int createId) { if (createId>0) { pClub pc = getClub(createId); if (pc) return pc; } pClub dbClub = oe->useRunnerDb() ? oe->runnerDB->getClub(pname) : 0; if (dbClub) { if (dbClub->getName() != pname) { pClub pc = getClub(dbClub->getName()); if (pc) return pc; } if (createId<=0) if (getClub(dbClub->Id)) createId = getFreeClubId(); //We found a db club, but Id is taken. else createId = dbClub->Id; oClub c(this, createId); c = *dbClub; c.Id = createId; return addClub(c); } else { if (createId==0) createId = getFreeClubId(); oClub c(this, createId); c.setName(pname); return addClub(c); } } pClub oEvent::addClub(const oClub &oc) { if (clubIdIndex.count(oc.Id)!=0) return clubIdIndex[oc.Id]; Clubs.push_back(oc); Clubs.back().addToEvent(); if (!oc.existInDB()) Clubs.back().synchronize(); clubIdIndex[Clubs.back().Id]=&Clubs.back(); return &Clubs.back(); } void oEvent::fillClubs(gdioutput &gdi, const string &id) { vector< pair > d; oe->fillClubs(d); gdi.addItem(id, d); } const vector< pair > & oEvent::fillClubs(vector< pair > &out) { out.clear(); //gdi.clearList(name); synchronizeList(oListId::oLClubId); Clubs.sort(); oClubList::iterator it; for (it=Clubs.begin(); it != Clubs.end(); ++it){ if (!it->Removed) out.push_back(make_pair(it->name, it->Id)); } return out; } void oClub::buildTableCol(oEvent *oe, Table *table) { oe->oClubData->buildTableCol(table); } #define TB_CLUBS "clubs" const shared_ptr &oClub::getTable(oEvent *oe) { if (!oe->hasTable("club")) { auto table = make_shared
(oe, 20, L"Klubbar", TB_CLUBS); table->addColumn("Id", 70, true, true); table->addColumn("Ändrad", 70, false); table->addColumn("Namn", 200, false); oe->oClubData->buildTableCol(table.get()); table->addColumn("Deltagare", 70, true); table->addColumn("Avgift", 70, true); table->addColumn("Betalat", 70, true); oe->setTable("club", table); } return oe->getTable("club"); } void oEvent::generateClubTableData(Table &table, oClub *addClub) { if (addClub) { addClub->addTableRow(table); return; } synchronizeList(oListId::oLClubId); oe->setupClubInfoData(); oClubList::iterator it; for (it=Clubs.begin(); it != Clubs.end(); ++it){ if (!it->isRemoved()){ it->addTableRow(table); } } } int oClub::getTableId() const { return Id; } void oClub::addTableRow(Table &table) const { table.addRow(getTableId(), pClass(this)); bool dbClub = table.getInternalName() != TB_CLUBS; bool canEdit = dbClub ? !oe->isClient() : true; pClub it = pClub(this); int row = 0; table.set(row++, *it, TID_ID, itow(getId()), false); table.set(row++, *it, TID_MODIFIED, getTimeStamp(), false); table.set(row++, *it, TID_CLUB, getName(), canEdit); row = oe->oClubData->fillTableCol(*this, table, canEdit); if (!dbClub) { table.set(row++, *it, TID_NUM, itow(tNumRunners), false); table.set(row++, *it, TID_FEE, oe->formatCurrency(tFee), false); table.set(row++, *it, TID_PAID, oe->formatCurrency(tPaid), false); } } pair oClub::inputData(int id, const wstring &input, int inputId, wstring &output, bool noUpdate) { synchronize(false); if (id>1000) { return oe->oClubData->inputData(this, id, input, inputId, output, noUpdate); } switch(id) { case TID_CLUB: setName(input); synchronize(); output = getName(); break; } return make_pair(0, false); } void oClub::fillInput(int id, vector< pair > &out, size_t &selected) { if (id>1000) { oe->oClubData->fillInput(this, id, 0, out, selected); return; } } void oEvent::mergeClub(int clubIdPri, int clubIdSec) { if (clubIdPri==clubIdSec) return; pClub pc = getClub(clubIdPri); if (!pc) return; // Update teams for (oTeamList::iterator it = Teams.begin(); it!=Teams.end(); ++it) { if (it->getClubId() == clubIdSec) { it->Club = pc; it->updateChanged(); it->synchronize(); } } // Update runners for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) { if (it->getClubId() == clubIdSec) { it->Club = pc; it->updateChanged(); it->synchronize(); } } oe->removeClub(clubIdSec); } void oEvent::getClubs(vector &c, bool sort) { if (sort) { synchronizeList(oListId::oLClubId); Clubs.sort(); } c.clear(); c.reserve(Clubs.size()); for (oClubList::iterator it = Clubs.begin(); it != Clubs.end(); ++it) { if (!it->isRemoved()) c.push_back(&*it); } } void oEvent::viewClubMembers(gdioutput &gdi, int clubId) { sortRunners(ClassStartTime); sortTeams(ClassStartTime, 0, true); gdi.fillDown(); gdi.dropLine(); int nr = 0; int nt = 0; // Update teams for (oTeamList::iterator it = Teams.begin(); it!=Teams.end(); ++it) { if (it->skip()) continue; if (it->getClubId() == clubId) { if (nt==0) gdi.addString("", 1, "Lag(flera)"); gdi.addStringUT(0, it->getName() + L", " + it->getClass(false) ); nt++; } } gdi.dropLine(); // Update runners for (oRunnerList::iterator it = Runners.begin(); it!=Runners.end(); ++it) { if (it->skip()) continue; if (it->getClubId() == clubId) { if (nr==0) gdi.addString("", 1, "Löpare:"); gdi.addStringUT(0, it->getName() + L", " + it->getClass(true) ); nr++; } } } void oClub::addInvoiceLine(gdioutput &gdi, const InvoiceLine &line, InvoiceData &data) const { int &yp = data.yp; for (size_t k = 0; k < line.xposAndString.size(); k++) { const pair > &entry = line.xposAndString[k]; int xp = entry.first; bool right = entry.second.first; const wstring &str = entry.second.second; if (right) gdi.addStringUT(yp, xp, normalText|textRight, str); else gdi.addStringUT(yp, xp, normalText, str); } data.total_fee_amount += line.fee; data.total_rent_amount += line.rent; data.total_paid_amount += line.paid; if (line.paid > 0) data.paidPerMode[line.payMode] += line.paid; yp += data.lh; } void oClub::addRunnerInvoiceLine(const pRunner r, bool inTeam, const map &definedPayModes, const InvoiceData &data, list &lines) const { int xs = data.xs; lines.push_back(InvoiceLine()); InvoiceLine &line = lines.back(); if (r->getTeam() && !inTeam && !r->isPatrolMember()) line.addString(xs, r->getName() + L" (" + r->getTeam()->getName() + L")"); else line.addString(xs + (inTeam ? 10 : 0), r->getName()); wstring ts; if (!inTeam) line.addString(xs+data.clsPos, r->getClass(true)); if (r->getStatus() == StatusUnknown) ts = L"-"; else if (!data.multiDay) { if (r->getStatus()==StatusOK) { ClassType type = oClassIndividual; cTeam t = r->getTeam(); if (t && r->getClassRef(false)) type = r->getClassRef(false)->getClassType(); if (type == oClassIndividRelay || type == oClassRelay) { int leg = r->getLegNumber(); if (t->getLegStatus(leg, true, false) == StatusOK) ts = t->getLegPlaceS(leg, false)+ L" (" + r->getRunningTimeS(true) + L")"; else ts = t->getLegStatusS(leg, true, false)+ L" (" + r->getRunningTimeS(true) +L")"; } else ts = r->getPrintPlaceS(true)+ L" (" + r->getRunningTimeS(true) + L")"; } else ts = r->getStatusS(true, true); } else { if (r->getTotalStatus()==StatusOK) { ts = r->getPrintTotalPlaceS(true) + L" (" + r->getTotalRunningTimeS() + L")"; } else if (r->getTotalStatus()!=StatusNotCompetiting) ts = r->getStatusS(true, true); else { ts = r->getInputStatusS(); } } int fee = r->getDCI().getInt("Fee"); int card = r->getDCI().getInt("CardFee"); int paid = r->getDCI().getInt("Paid"); int pm = r->getPaymentMode(); /*string payMode = ""; map::const_iterator res = definedPayModes.find(pm); if (res != definedPayModes.end()) payMode = ", " + res->second; */ if (r->getClassRef(false) && r->getClassRef(false)->getClassStatus() == oClass::ClassStatus::InvalidRefund) { fee = 0; card = 0; } if (fee>0) line.addString(xs+data.feePos, oe->formatCurrency(fee), true); if (card > 0) line.addString(xs+data.cardPos, oe->formatCurrency(card), true); if (paid>0) line.addString(xs+data.paidPos, oe->formatCurrency(paid), true); line.fee= fee; if (card > 0) line.rent = card; line.paid = paid; line.payMode = pm; line.addString(xs+data.resPos, ts); } void oClub::addTeamInvoiceLine(const pTeam t, const map &definedPayModes, const InvoiceData &data, list &lines) const { lines.push_back(InvoiceLine()); InvoiceLine &line = lines.back(); int xs = data.xs; int fee = t->getDCI().getInt("Fee"); int paid = t->getDCI().getInt("Paid"); if (fee <= 0) return; line.addString(xs, t->getName()); line.addString(xs+data.clsPos, t->getClass(false)); wstring ts; if (t->getStatus() == StatusUnknown) ts = L"-"; else { if (t->getStatus()==StatusOK) { ts = t->getPrintPlaceS(true) + L" (" + t->getRunningTimeS(true) + L")"; } else ts = t->getStatusS(true, true); } if (t->getClassRef(false) && t->getClassRef(false)->getClassStatus() == oClass::ClassStatus::InvalidRefund) { fee = 0; } line.addString(xs+data.feePos, oe->formatCurrency(fee), true); line.addString(xs+data.paidPos, oe->formatCurrency(paid), true); line.fee = fee; line.paid = paid; line.payMode = t->getPaymentMode(); line.addString(xs+data.resPos, ts); for (int j = 0; j < t->getNumRunners(); j++) { pRunner r = t->getRunner(j); if (r && r->getClubId() == t->getClubId()) { addRunnerInvoiceLine(r, true, definedPayModes, data, lines); } } } void oClub::generateInvoice(gdioutput &gdi, int &toPay, int &hasPaid, const map &definedPayModes, map &paidPerMode) { wstring account = oe->getDI().getString("Account"); wstring pdate = oe->getDI().getDate("PaymentDue"); int pdateI = oe->getDI().getInt("PaymentDue"); wstring organizer = oe->getDI().getString("Organizer"); int number = getDCI().getInt("InvoiceNo"); if (number == 0) { assignInvoiceNumber(*oe, false); number = getDCI().getInt("InvoiceNo"); } gdi.fillDown(); if (account.empty()) gdi.addString("", 0, "Varning: Inget kontonummer angivet (Se tävlingsinställningar).").setColor(colorRed); if (pdateI == 0) gdi.addString("", 0, "Varning: Inget sista betalningsdatum angivet (Se tävlingsinställningar).").setColor(colorRed); if (organizer.empty()) gdi.addString("", 0, "Varning: Ingen organisatör/avsändare av fakturan angiven (Se tävlingsinställningar).").setColor(colorRed); vector runners; oe->getClubRunners(getId(), runners); vector teams; oe->getClubTeams(getId(), teams); toPay = 0; hasPaid = 0; if (runners.empty() && teams.empty()) return; int ys = gdi.getCY(); int lh = gdi.getLineHeight(); InvoiceData data(lh); data.xs = 30; const int &xs = data.xs; data.adrPos = gdi.scaleLength(350); data.clsPos = gdi.scaleLength(270); data.feePos = gdi.scaleLength(390); data.cardPos = gdi.scaleLength(440); data.paidPos = gdi.scaleLength(490); data.resPos = gdi.scaleLength(550); gdi.addString("", ys, xs+data.adrPos, boldHuge, "FAKTURA"); if (number > 0) { gdi.addStringUT(ys + lh * 3, xs + data.adrPos, fontMedium, lang.tl("Faktura nr") + L": " + itow(number)); gdi.addStringUT(ys + lh * 4, xs + data.adrPos, fontMedium, getInvoiceDate(*oe)); } int &yp = data.yp; yp = ys+lh * 2; wstring ostreet = oe->getDI().getString("Street"); wstring oaddress = oe->getDI().getString("Address"); wstring oco = oe->getDI().getString("CareOf"); if (!organizer.empty()) gdi.addStringUT(yp, xs, fontMedium, organizer), yp+=lh; if (!oco.empty()) gdi.addStringUT(yp, xs, fontMedium, oco), yp+=lh; if (!ostreet.empty()) gdi.addStringUT(yp, xs, fontMedium, ostreet), yp+=lh; if (!oaddress.empty()) gdi.addStringUT(yp, xs, fontMedium, oaddress), yp+=lh; yp+=lh; gdi.addStringUT(yp, xs, fontLarge, oe->getName()); gdi.addStringUT(yp+lh*2, xs, fontMedium, oe->getDate()); wstring co = getDCI().getString("CareOf"); wstring address = getDCI().getString("Street"); wstring city = getDCI().getString("ZIP") + L" " + getDCI().getString("City"); wstring country = getDCI().getString("Country"); int ayp = ys + gdi.scaleLength(122); const int absX = oe->getPropertyInt("addressxpos", 125); int absY = oe->getPropertyInt("addressypos", 50); const int absYL = 5; gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, getName()).setAbsPrintPos(absX,absY); ayp+=lh; absY+=absYL; if (!co.empty()) gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, co).setAbsPrintPos(absX,absY), ayp+=lh, absY+=absYL; if (!address.empty()) gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, address).setAbsPrintPos(absX,absY), ayp+=lh, absY+=absYL; if (!city.empty()) gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, city).setAbsPrintPos(absX,absY), ayp+=lh, absY+=absYL; if (!country.empty()) gdi.addStringUT(ayp, xs+data.adrPos, fontMedium, country).setAbsPrintPos(absX,absY), ayp+=lh, absY+=absYL; yp = ayp+gdi.scaleLength(36); gdi.addString("", yp, xs, boldSmall, "Deltagare"); gdi.addString("", yp, xs+data.clsPos, boldSmall, "Klass"); gdi.addString("", yp, xs+data.feePos, boldSmall|textRight, "Avgift"); gdi.addString("", yp, xs+data.cardPos, boldSmall|textRight, "Brickhyra"); gdi.addString("", yp, xs+data.paidPos, boldSmall|textRight, "Betalat"); gdi.addString("", yp, xs+data.resPos, boldSmall, "Resultat"); yp += lh; data.multiDay = oe->hasPrevStage(); list lines; for (size_t k=0;kgetTeam(); if (team && team->getDCI().getInt("Fee") > 0 && team->getClubId() == runners[k]->getClubId()) continue; // Show this line under the team. addRunnerInvoiceLine(runners[k], false, definedPayModes, data, lines); } for (size_t k=0;k::iterator it = lines.begin(); it != lines.end(); ++it) { addInvoiceLine(gdi, *it, data); } yp += lh; gdi.addStringUT(yp, xs+data.feePos, boldText|textRight, oe->formatCurrency(data.total_fee_amount)); gdi.addStringUT(yp, xs+data.cardPos, boldText|textRight, oe->formatCurrency(data.total_rent_amount)); gdi.addStringUT(yp, xs+data.paidPos, boldText|textRight, oe->formatCurrency(data.total_paid_amount)); yp+=lh*2; toPay = data.total_fee_amount+data.total_rent_amount-data.total_paid_amount; hasPaid = data.total_paid_amount; for (map::iterator it = data.paidPerMode.begin(); it != data.paidPerMode.end(); ++it) { paidPerMode[it->first] += it->second; } gdi.addString("", yp, xs, boldText, L"Att betala: X#" + oe->formatCurrency(toPay)); gdi.updatePos(gdi.scaleLength(710),0,0,0); yp+=lh*2; gdi.addStringUT(yp, xs, normalText, lang.tl(L"Vänligen betala senast ") + pdate + lang.tl(L" till ") + account + L"."); gdi.dropLine(2); //gdi.addStringUT(gdi.getCY()-1, 1, pageNewPage, blank, 0, 0); vector< pair > mlines; oe->getExtraLines("IVExtra", mlines); for (size_t k = 0; k < mlines.size(); k++) { gdi.addStringUT(mlines[k].second, mlines[k].first); } if (mlines.size()>0) gdi.dropLine(0.5); gdi.addStringUT(gdi.getCY()-1, xs, pageNewPage, "", 0, 0).setExtra(START_YP); gdi.dropLine(); } void oEvent::getClubRunners(int clubId, vector &runners) const { oRunnerList::const_iterator rit; runners.clear(); for (rit=Runners.begin(); rit != Runners.end(); ++rit) { if (!rit->skip() && rit->getClubId() == clubId) runners.push_back(pRunner(&*rit)); } } void oEvent::getClubTeams(int clubId, vector &teams) const { oTeamList::const_iterator rit; teams.clear(); for (rit=Teams.begin(); rit != Teams.end(); ++rit) { if (!rit->skip() && rit->getClubId() == clubId) teams.push_back(pTeam(&*rit)); } } void oClub::definedPayModes(oEvent &oe, map &definedPayModes) { vector< pair > modes; oe.getPayModes(modes); if (modes.size() > 1) { for (size_t k = 0; k < modes.size(); k++) { definedPayModes[modes[k].second] = modes[k].first; } } } void oEvent::printInvoices(gdioutput &gdi, InvoicePrintType type, const wstring &basePath, bool onlySummary) { map definedPayModes; oClub::definedPayModes(*this, definedPayModes); map paidPerMode; oClub::assignInvoiceNumber(*this, false); oClubList::iterator it; oe->calculateTeamResults(set(), ResultType::ClassResult); oe->sortTeams(ClassStartTime, 0, true); oe->calculateResults(set(), ResultType::ClassResult); oe->sortRunners(ClassStartTime); int pay, paid; vector fees, vpaid; set clubId; fees.reserve(Clubs.size()); int k=0; bool toFile = type > 10; wstring path = basePath; if (basePath.size() > 0 && *basePath.rbegin() != '\\' && *basePath.rbegin() != '/') path.push_back('\\'); if (toFile) { ofstream fout; if (type == IPTElectronincHTML) fout.open((path + L"invoices.txt").c_str()); for (it=Clubs.begin(); it != Clubs.end(); ++it) { if (!it->isRemoved()) { gdi.clearPage(false); int nr = it->getDCI().getInt("InvoiceNo"); wstring filename; if (type == IPTElectronincHTML) filename = L"invoice" + itow(nr*197) + L".html"; else if (type == IPTAllPDF) filename = lang.tl(L"Faktura ") + makeValidFileName(it->getDisplayName(), false) + L" (" + itow(nr) + L").pdf"; else filename = lang.tl(L"Faktura ") + makeValidFileName(it->getDisplayName(), false) + L" (" + itow(nr) + L").html"; wstring email = it->getDCI().getString("EMail"); bool hasEmail = !(email.empty() || email.find_first_of('@') == email.npos); if (type == IPTElectronincHTML) { if (!hasEmail) continue; } it->generateInvoice(gdi, pay, paid, definedPayModes, paidPerMode); if (type == IPTElectronincHTML && pay > 0) { fout << it->getId() << ";" << gdi.toUTF8(it->getName()) << ";" << nr << ";" << gdi.toUTF8(filename) << ";" << gdi.toUTF8(email) << ";" << gdi.toUTF8(formatCurrency(pay)) <getId()); fees.push_back(pay); vpaid.push_back(paid); } gdi.clearPage(true); } } else { for (it=Clubs.begin(); it != Clubs.end(); ++it) { if (!it->isRemoved()) { wstring email = it->getDCI().getString("EMail"); bool hasEmail = !(email.empty() || email.find_first_of('@') == email.npos); if (type == IPTNoMailPrint && hasEmail) continue; it->generateInvoice(gdi, pay, paid, definedPayModes, paidPerMode); clubId.insert(it->getId()); fees.push_back(pay); vpaid.push_back(paid); } } } if (onlySummary) gdi.clearPage(true); k=0; gdi.dropLine(1); gdi.addString("", boldLarge, "Sammanställning, ekonomi"); int yp = gdi.getCY() + 10; gdi.addString("", yp, 50, boldText, "Faktura nr"); gdi.addString("", yp, 240, boldText|textRight, "KlubbId"); gdi.addString("", yp, 250, boldText, "Klubb"); gdi.addString("", yp, 550, boldText|textRight, "Faktura"); gdi.addString("", yp, 620, boldText|textRight, "Kontant"); yp+=gdi.getLineHeight()+3; int sum = 0, psum = 0; for (it=Clubs.begin(); it != Clubs.end(); ++it) { if (!it->isRemoved() && clubId.count(it->getId()) > 0) { gdi.addStringUT(yp, 50, fontMedium, itos(it->getDCI().getInt("InvoiceNo"))); if (it->getExtIdentifier() != 0) gdi.addStringUT(yp, 240, textRight|fontMedium, it->getExtIdentifierString()); gdi.addStringUT(yp, 250, fontMedium, it->getName()); gdi.addStringUT(yp, 550, fontMedium|textRight, oe->formatCurrency(fees[k])); gdi.addStringUT(yp, 620, fontMedium|textRight, oe->formatCurrency(vpaid[k])); sum+=fees[k]; psum+=vpaid[k]; k++; yp+=gdi.getLineHeight(); } } yp+=gdi.getLineHeight(); gdi.fillDown(); gdi.addStringUT(yp, 550, boldText|textRight, lang.tl(L"Totalt faktureras: ") + oe->formatCurrency(sum)); gdi.addStringUT(yp+gdi.getLineHeight(), 550, boldText|textRight, lang.tl(L"Totalt kontant: ") + oe->formatCurrency(psum)); gdi.dropLine(0.5); if (definedPayModes.size() > 1) { vector< pair > modes; oe->getPayModes(modes); for (k = 0; k < int(modes.size()); k++) { int ppm = paidPerMode[k]; if (ppm > 0) { gdi.addStringUT(gdi.getCY(), 550, normalText|textRight, modes[k].first + L": " + oe->formatCurrency(ppm)); } } } } void oClub::updateFromDB() { if (!oe->useRunnerDb()) return; pClub pc = oe->runnerDB->getClub(Id); if (pc && !pc->sameClub(*this)) pc = 0; if (pc==0) pc = oe->runnerDB->getClub(name); if (pc) { memcpy(oData, pc->oData, sizeof (oData)); updateChanged(); } } void oEvent::updateClubsFromDB() { if (!oe->useRunnerDb()) return; oClubList::iterator it; for (it=Clubs.begin();it!=Clubs.end();++it) { it->updateFromDB(); it->synchronize(); } } bool oClub::sameClub(const oClub &c) { return _wcsicmp(name.c_str(), c.name.c_str())==0; } void oClub::remove() { if (oe) oe->removeClub(Id); } bool oClub::canRemove() const { return !oe->isClubUsed(Id); } void oEvent::setupClubInfoData() { if (tClubDataRevision == dataRevision || Clubs.empty()) return; inthashmap fee(Clubs.size()); inthashmap paid(Clubs.size()); inthashmap runners(Clubs.size()); // Individual fees for (oRunnerList::iterator it = Runners.begin(); it != Runners.end(); ++it) { if (it->isRemoved()) continue; oRunner &r = *it; if (r.Club) { int id = r.Club->Id; ++runners[id]; oDataConstInterface di = r.getDCI(); bool skip = r.Class && r.Class->getClassStatus() == oClass::ClassStatus::InvalidRefund; if (!skip) { int cardFee = di.getInt("CardFee"); if (cardFee < 0) cardFee = 0; fee[id] += di.getInt("Fee") + cardFee; } paid[id] += di.getInt("Paid"); } } // Team fees for (oTeamList::iterator it = Teams.begin(); it != Teams.end(); ++it) { if (it->isRemoved()) continue; oTeam &t = *it; if (t.Club) { int id = t.Club->Id; oDataConstInterface di = t.getDCI(); bool skip = t.Class && t.Class->getClassStatus() == oClass::ClassStatus::InvalidRefund; if (!skip) { fee[id] += di.getInt("Fee"); } paid[id] += di.getInt("Paid"); } } for (oClubList::iterator it = Clubs.begin(); it != Clubs.end(); ++it) { int id = it->Id; it->tFee = fee[id]; it->tPaid = paid[id]; it->tNumRunners = runners[id]; } tClubDataRevision = dataRevision; } bool oClub::isVacant() const { return getId() == oe->getVacantClubIfExist(false); } void oClub::changeId(int newId) { pClub old = oe->clubIdIndex[Id]; if (old == this) oe->clubIdIndex.remove(Id); oBase::changeId(newId); oe->clubIdIndex[newId] = this; } void oClub::clearClubs(oEvent &oe) { vector r; oe.getRunners(0, 0, r, false); for (size_t k = 0; ksetClubId(0); r[k]->synchronize(true); } vector t; oe.getTeams(0, t, false); for (size_t k = 0; ksetClubId(0); t[k]->synchronize(true); } vector c; oe.getClubs(c, false); for (size_t k = 0; kgetId()); } } void oClub::assignInvoiceNumber(oEvent &oe, bool reset) { oe.synchronizeList(oListId::oLClubId); oe.Clubs.sort(); int numberStored = oe.getPropertyInt("FirstInvoice", 100); int number = numberStored; if (!reset) { int maxInvoice = 0; for (oClubList::iterator it = oe.Clubs.begin(); it != oe.Clubs.end(); ++it) { if (it->isRemoved()) continue; int no = it->getDCI().getInt("InvoiceNo"); maxInvoice = max(maxInvoice, no); } if (maxInvoice != 0) number = maxInvoice + 1; else reset = true; // All zero } for (oClubList::iterator it = oe.Clubs.begin(); it != oe.Clubs.end(); ++it) { if (it->isRemoved()) continue; if (reset || it->getDCI().getInt("InvoiceNo") == 0) { it->getDI().setInt("InvoiceNo", number++); it->synchronize(true); } } if (number > numberStored) oe.setProperty("FirstInvoice", number); } int oClub::getFirstInvoiceNumber(oEvent &oe) { oe.synchronizeList(oListId::oLClubId); int number = 0; for (oClubList::iterator it = oe.Clubs.begin(); it != oe.Clubs.end(); ++it) { if (it->isRemoved()) continue; int no = it->getDCI().getInt("InvoiceNo"); if (no > 0) { if (number == 0) number = no; else number = min(number, no); } } return number; } void oClub::changedObject() { if (oe) oe->globalModification = true; } bool oClub::operator<(const oClub &c) const { return CompareString(LOCALE_USER_DEFAULT, 0, name.c_str(), name.length(), c.name.c_str(), c.name.length()) == CSTR_LESS_THAN; } wstring oClub::getInvoiceDate(oEvent &oe) { wstring invoiceDate = oe.getDCI().getDate("InvoiceDate"); int invoiceDateI = oe.getDCI().getInt("InvoiceDate"); if (invoiceDateI == 0) { invoiceDate = getLocalDate(); setInvoiceDate(oe, invoiceDate); } return invoiceDate; } void oClub::setInvoiceDate(oEvent &oe, const wstring &id) { oe.getDI().setDate("InvoiceDate", id); }