#include #include #include #include #include #include #include #include #include "sc1400.h" #include "../cg/cg2101.h" #include "../cg/cg2103.h" #include "../cg/cgsaldac.h" #include /////////////////////////////////////////////////////////// // TAbbuona_sheet /////////////////////////////////////////////////////////// enum { C_CHECKED, C_GRUPPO, C_CONTO, C_CODCF, C_RAGSOC, C_IMPORTO, C_RESIDUO, C_CODVAL, C_DATASCAD, C_ANNO, C_PARTITA, C_RIGA, C_RATA }; class TAbbuona_sheet : public TArray_sheet { virtual bool get_cell_colors(int row, int col, COLOR& fore, COLOR& back) const; public: TAbbuona_sheet(); }; bool TAbbuona_sheet::get_cell_colors(int /*row*/, int col, COLOR& fore, COLOR& back) const { if (col == C_RESIDUO) // Evidenzia la colonna del residuo { fore = NORMAL_COLOR; back = REQUIRED_BACK_COLOR; return true; } return false; } TAbbuona_sheet::TAbbuona_sheet() : TArray_sheet(0, 0, 0, 0, TR("Scadenze aperte"), HR("@1C|Grp.@3|Cnt.@3|Codice@R|Ragione Sociale@50|Importo@10R|Residuo@10R|Val.|Data@10|Anno@R|Partita@8R|Riga@R|Rata@R"), 0x1, 1) {} /////////////////////////////////////////////////////////// // TAbbuona_mask /////////////////////////////////////////////////////////// class TAbbuona_mask : public TAutomask { protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); void auto_proponi(short id, bool last); // Propone il primo/ultimo record del cursore associato al campo id public: TAbbuona_mask() : TAutomask("sc1400a") {} }; void TAbbuona_mask::auto_proponi(short id, bool last) { TEdit_field& e =efield(id); TBrowse& b = *e.browse(); TCursor& c = *b.cursor(); b.do_input(true); // Reimposta filtri const TRecnotype items = c.items(); if (items > 0) { c = last ? (items-1): 0L; // Si posiziona sul primo buono if (c.ok()) { b.do_output(); // Lo propone automaticamente e.set_dirty(); } } } bool TAbbuona_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_TIPOCF: case F_INVALUTA: if (e == fe_modify) auto_proponi(F_CAUSALE, false); break; case F_CODVAL: if (e == fe_modify) { if (is_true_value(o.get())) auto_proponi(F_DATACAMBIO, true); else set(F_INVALUTA, "", 0x1); } break; case F_IMPORTO: if (e == fe_init && o.empty()) o.set(50); break; case F_CAUSALE: if (e == fe_init) auto_proponi(F_CAUSALE, false); if (e == fe_modify || e == fe_close) { const TCausale caus(o.get()); const int riga_abb = get(F_TIPOCF) == "C" ? RIGA_ABBUONI_PASSIVI : RIGA_ABBUONI_ATTIVI; TBill conto_abbuoni; caus.bill(riga_abb, conto_abbuoni); if (!conto_abbuoni.find()) return error_box(TR("Il conto per gli abbuoni alla riga %d della causale non è valido"), riga_abb); if (get_bool(F_INVALUTA)) { TBill conto_diffcam; caus.bill(RIGA_DIFFCAM, conto_diffcam); if (!conto_diffcam.find()) return error_box(TR("Il conto per le differenze cambi della causale non è valido")); } } break; case F_DATACOMP: if (e == fe_close) { const TDate datareg = get(F_DATAREG); TDate datacomp = o.get(); if (!datacomp.ok() || datacomp > datareg) { datacomp = datareg; o.set(datacomp.string()); } } break; default: break; } return true; } /////////////////////////////////////////////////////////// // TAbbuona_partite /////////////////////////////////////////////////////////// class TAbbuona_partite : public TSkeleton_application { protected: // Applicat virtual void main_loop(); bool genera_abbuono(TPartita& game, int nriga, int nrata, const TMovimentoPN& mov, TLog_report& log) const; public: void fill_sheet(const char tipocf, const TCurrency& impmin, TAbbuona_sheet& sheet); bool elabora(const TMask& msk, TAbbuona_sheet& sheet) const; }; void TAbbuona_partite::fill_sheet(const char tipocf, const TCurrency& imp_min, TAbbuona_sheet& sheet) { const bool in_valuta = !imp_min.is_firm_value(); const TString4 cod_val = in_valuta ? imp_min.get_value() : EMPTY_STRING; const TCurrency zero_val(ZERO, cod_val); TString query; // Selezione delle scadenze aperte query << "USE SCAD\n" << "SELECT (PAGATA!=\"X\")&&(BLOCCATA!=\"X\")\n" << "FROM TIPOC=" << tipocf << "\nTO TIPOC=" << tipocf; TISAM_recordset scadenze(query); const TRectype& scad = scadenze.cursor()->curr(); TString msg; msg << TR("Elaborazione scadenze aperte per meno di ") << imp_min.string(true) << ' '; msg << (in_valuta ? cod_val : TCurrency::get_firm_val()); TProgind pi(scadenze.items(), msg); TToken_string row; // Riga di lavoro sullo sheet for (bool ok = scadenze.move_first(); ok; ok = scadenze.move_next()) { if (!pi.addstatus(1)) break; row.cut(0) << tipocf; row.add(0); row.add(0); row.add(scad.get(SCAD_SOTTOCONTO)); row.add(scad.get(SCAD_ANNO)); row.add(scad.get(SCAD_NUMPART)); row.add(scad.get(SCAD_NRIGA)); const TRectype& game_rec = cache().get(LF_PARTITE, row); // Ignora partite con la valuta incompatibile const TString& game_val = game_rec.get(PART_CODVAL); if (in_valuta) { if (game_val != cod_val) continue; } else { if (is_true_value(game_val)) continue; } TPartita partita(game_rec); const int nriga = scad.get_int(SCAD_NRIGA); const int nrata = scad.get_int(SCAD_NRATA); TRiga_scadenze& rata = partita.riga(nriga).rata(nrata); TImporto imp_res = rata.residuo(in_valuta); imp_res.normalize(tipocf == 'C' ? 'D' : 'A'); const TCurrency residuo(imp_res.valore(), cod_val); if (residuo > zero_val && residuo <= imp_min) { TImporto imp_val = rata.importo(in_valuta); imp_val.normalize(imp_res.sezione()); const TCurrency importo(imp_val.valore(), cod_val); const TBill& conto = partita.conto(); row = "X"; row.add(game_rec.get(PART_GRUPPOCL)); row.add(game_rec.get(PART_CONTOCL)); row.add(conto.codclifo()); row.add(conto.descrizione()); row.add(importo.string(true)); row.add(residuo.string(true)); row.add(cod_val); row.add(scad.get(SCAD_DATASCAD)); row.add(scad.get(SCAD_ANNO)); row.add(scad.get(SCAD_NUMPART)); row.add(nriga); row.add(nrata); sheet.add(row); } } } bool TAbbuona_partite::genera_abbuono(TPartita& game, int nriga, int nrata, const TMovimentoPN& mov, TLog_report& log) const { TString msg; msg.format(FR(" %d della riga %d della partita %d/%s"), nrata, nriga, game.anno(), (const char*)game.numero()); if (!game.esiste(nriga, nrata)) // Non si sa mai col saldaconto! { msg.insert(TR("Non esiste la rata")); log.log(1, msg); return false; } const TRectype& head = mov.curr(); const TValuta valuta(head); // Creo una riga di partita di tipo pagamento e ci copio i dati della testata del movimento TRiga_partite& riga = game.new_row(); const int nrigp = riga.get_int(PART_NRIGA); riga.put(PART_TIPOMOV, tm_pagamento); riga.put(PART_SEZ, game.conto().tipo() == 'F' ? 'D' : 'A'); riga.put(PART_NREG, head.get(MOV_NUMREG)); riga.put(PART_NUMRIG, mov.cg_items()); riga.put(PART_DATAREG, head.get(MOV_DATAREG)); riga.put(PART_DATAPAG, head.get(MOV_DATACOMP)); riga.put(PART_CODCAUS, head.get(MOV_CODCAUS)); riga.put(PART_NUMDOC, head.get(MOV_NUMDOC)); riga.put(PART_DATADOC, head.get(MOV_DATADOC)); riga.put(PART_DESCR, head.get(MOV_DESCR)); if (valuta.in_valuta()) valuta.put(riga); // Creo una nuova riga di pagamento assegnado il flag di saldo TRiga_scadenze& scad = game.rata(nriga, nrata); TRectype new_pag = scad.new_row(nrigp); // Creo nuova riga e la duplico new_pag.put(PAGSCA_ACCSAL, 'S'); // Pongo pagamento a saldo const bool empty = game.modifica_pagamento(new_pag, valuta, true); if (empty) { msg.insert(TR("Errore di chiusura della rata")); log.log(2, msg); } else { msg.insert(TR("Chiusa rata")); log.log(0, msg); } return !empty; } bool TAbbuona_partite::elabora(const TMask& msk, TAbbuona_sheet& scad_sheet) const { // La validità di tutti questi campi è già garantita dai controlli di msk const char tipo_cf = msk.get(F_TIPOCF)[0]; const TDate datareg = msk.get(F_DATAREG); const TDate datacomp = msk.get(F_DATACOMP); const TValuta valuta(msk, F_CODVAL, F_DATACAMBIO, F_CAMBIO); const TCausale caus(msk.get(F_CAUSALE), datareg.year()); const int riga_abb = tipo_cf == 'C' ? RIGA_ABBUONI_PASSIVI : RIGA_ABBUONI_ATTIVI; TBill conto_abbuoni; caus.bill(riga_abb, conto_abbuoni); TBill conto_diffcam; if (valuta.in_valuta()) caus.bill(RIGA_DIFFCAM, conto_diffcam); TMovimentoPN mov; TRectype& head = mov.curr(); head.put(MOV_CODCAUS, msk.get(F_CAUSALE)); head.put(MOV_DATAREG, datareg); head.put(MOV_DATACOMP, datacomp); head.put(MOV_DESCR, TR("Abbuoni automatici")); if (valuta.in_valuta()) valuta.put(head); if (mov.write() != NOERR) return error_box(TR("Impossibile creare il movimento di prima nota")); const long numreg = head.get_long(MOV_NUMREG); // Numero registrazione per saldaconto TLog_report log; TString msg; msg << TR("Creazione della testata del movimento n.") << numreg; log.log(1, msg); TPartite_array partite; bool can_write = true; TBill last_clifo; FOR_EACH_CHECKED_ROW(scad_sheet, r, row) { const TBill bill(row->get_int(C_GRUPPO), row->get_int(C_CONTO), row->get_long(C_CODCF), tipo_cf); const int anno = row->get_int(C_ANNO); const TString8 numpart = row->get(C_PARTITA); const int nriga = row->get_int(C_RIGA); const int nrata = row->get_int(C_RATA); TPartita& game = partite.partita(bill, anno, numpart); if (bill != last_clifo) { log.log(0, msg.cut(0)); msg << TR("Elaborazione scadenze ") << bill.descrizione(); log.log(1, msg); TRectype& new_rmov = mov.cg(-1); bill.put(new_rmov); new_rmov.put(RMV_ROWTYPE, 'K'); last_clifo = bill; } if (!genera_abbuono(game, nriga, nrata, mov, log)) can_write = false; } TImporto abbuoni, diffcam; for (int i = 0; i < mov.cg_items(); i++) { // Calcola importo speso sul saldaconto per ogni riga contabile TImporto abb = partite.importo_speso(numreg, i+1, false, 0x2); abbuoni -= abb; // Aggiungi abbuono al relativo totalizzatore TImporto imp = abb; TImporto dic; if (valuta.in_valuta()) { dic = partite.importo_speso(numreg, i+1, false, 0x4); diffcam -= dic; // Aggiungi differenza cambi al relativo totalizzatore imp += dic; imp.normalize(); } TRectype& rmov = mov.cg(i); rmov.put(RMV_SEZIONE, imp.sezione()); rmov.put(RMV_IMPORTO, imp.valore()); } if (abbuoni.is_zero()) { log.log(2, TR("Il totale degli abbuoni è nullo.")); can_write = false; } else { abbuoni.normalize(); TRectype& rmov = mov.cg(-1); rmov.put(RMV_ROWTYPE, tipo_cf == 'F' ? 'A' : 'P'); // Abbuoni attivi o passivi? rmov.put(RMV_SEZIONE, abbuoni.sezione()); rmov.put(RMV_IMPORTO, abbuoni.valore()); conto_abbuoni.put(rmov); } if (!diffcam.is_zero()) { diffcam.normalize(); TRectype& rmov = mov.cg(-1); rmov.put(RMV_ROWTYPE, 'C'); // Differenze cambio rmov.put(RMV_SEZIONE, diffcam.sezione()); rmov.put(RMV_IMPORTO, diffcam.valore()); conto_diffcam.put(rmov); } if (can_write) { if (mov.rewrite() == NOERR) { partite.write(true); log.log(0, msg.cut(0)); msg << TR("Aggiornato saldaconto legato al movimento n.") << numreg; log.log(1, msg); } else { log.log(2, "Impossibile aggiornare il saldaconto"); can_write = false; } } if (!can_write) { const int err = mov.remove(); msg = err == NOERR ? TR("Eliminato") : TR("Impossibile eliminare"); msg << TR(" il movimento n.") << numreg; log.log(1, msg); } log.preview(); return can_write; } void TAbbuona_partite::main_loop() { TAbbuona_mask msk; while (msk.run() == K_ENTER) { const char tipo_cf = msk.get(F_TIPOCF)[0]; TCurrency imp_min; msk.get_currency(F_IMPORTO, imp_min); TAbbuona_sheet scad_sheet; fill_sheet(tipo_cf, imp_min, scad_sheet); if (scad_sheet.run() == K_ENTER && scad_sheet.one_checked()) elabora(msk, scad_sheet); } } int sc1400(int argc, char** argv) { TAbbuona_partite a; a.run(argc, argv, TR("Abbuoni automatici")); return 0; }