diff --git a/card.php b/card.php index 5486992..7a63fee 100755 --- a/card.php +++ b/card.php @@ -337,6 +337,32 @@ if ($action == 'searchinvoice' && $object->id > 0) { } } +// Create various payment (for transactions without invoices) +if ($action == 'confirmcreatevarious' && $object->id > 0 && $object->status == BankImportTransaction::STATUS_NEW) { + $accountancyCode = GETPOST('accountancy_code', 'alpha'); + $subledgerAccount = GETPOST('subledger_account', 'alpha'); + $sens = GETPOSTINT('sens'); + $variousLabel = GETPOST('various_label', 'alphanohtml'); + + if (empty($accountancyCode)) { + setEventMessages($langs->trans("ErrorFieldRequired", $langs->transnoentities("AccountingAccount")), null, 'errors'); + } else { + $bankAccountId = getDolGlobalInt('BANKIMPORT_BANK_ACCOUNT_ID'); + if (empty($bankAccountId)) { + setEventMessages($langs->trans("ErrorNoBankAccountConfigured"), null, 'errors'); + } else { + $result = $object->createVariousPayment($user, $bankAccountId, $accountancyCode, $sens, $variousLabel, $subledgerAccount); + if ($result > 0) { + setEventMessages($langs->trans("VariousPaymentCreated"), null, 'mesgs'); + header("Location: ".$_SERVER["PHP_SELF"]."?id=".$object->id); + exit; + } else { + setEventMessages($object->error, null, 'errors'); + } + } + } +} + /* * View */ @@ -563,6 +589,36 @@ if ($object->id > 0) { } } + // Various payment (no invoice, linked via bank_url) + if (empty($object->fk_paiement) && empty($object->fk_paiementfourn) && $object->fk_bank > 0) { + $sql = "SELECT url_id FROM ".MAIN_DB_PREFIX."bank_url WHERE fk_bank = ".((int) $object->fk_bank)." AND type = 'payment_various'"; + $resql = $db->query($sql); + if ($resql && $db->num_rows($resql) > 0) { + $obj = $db->fetch_object($resql); + require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php'; + $various = new PaymentVarious($db); + $various->fetch($obj->url_id); + + print ''; + print ''.$langs->trans("Payment").''; + print ''; + print ''; + print img_picto('', 'payment', 'class="pictofixedwidth"'); + print $langs->trans("VariousPayment").' #'.$various->id; + print ''; + print ' ('.dol_print_date($various->datep, 'day').' - '.price($various->amount, 0, $langs, 1, -1, 2, 'EUR').')'; + print ''; + print ''; + + if (!empty($various->accountancy_code)) { + print ''; + print ''.$langs->trans("AccountingAccount").''; + print ''.dol_escape_htmltag($various->accountancy_code).''; + print ''; + } + } + } + // If no payment link but invoice link exists (edge case) if (empty($object->fk_paiement) && empty($object->fk_paiementfourn)) { if ($object->fk_facture_fourn > 0) { @@ -677,6 +733,9 @@ if ($object->id > 0) { // Find matches button print ''.$langs->trans("FindMatches").''; + // Create various payment button + print ''.$langs->trans("CreateVariousPayment").''; + // Set as ignored print ''.$langs->trans("SetAsIgnored").''; } @@ -693,6 +752,94 @@ if ($object->id > 0) { print ''; + // Various payment inline form + if ($action == 'createvarious' && $object->status == BankImportTransaction::STATUS_NEW) { + // Auto-detect sens from amount sign: positive = credit (1), negative = debit (0) + $defaultSens = ($object->amount >= 0) ? 1 : 0; + $defaultLabel = $object->name.' - '.dol_trunc($object->description, 80); + + require_once DOL_DOCUMENT_ROOT.'/core/class/html.formaccounting.class.php'; + $formaccounting = new FormAccounting($db); + + print '
'; + print load_fiche_titre($langs->trans("CreateVariousPayment"), '', 'object_payment'); + + print '
'; + print ''; + print ''; + print ''; + + print ''; + + // Amount (read-only) + print ''; + print ''; + print ''; + print ''; + + // Date (read-only) + print ''; + print ''; + print ''; + print ''; + + // Counterparty (read-only) + print ''; + print ''; + print ''; + print ''; + + // Accounting account (Select2 search) + print ''; + print ''; + print ''; + print ''; + + // Subledger account (Select2 search) + print ''; + print ''; + print ''; + print ''; + + // Debit/Credit (auto-selected) + print ''; + print ''; + print ''; + print ''; + + // Label (editable, pre-filled) + print ''; + print ''; + print ''; + print ''; + + print '
'.$langs->trans("Amount").''; + $amountColor = ($object->amount >= 0) ? 'green' : 'red'; + print ''.price($object->amount, 0, $langs, 1, -1, 2, 'EUR').''; + print '
'.$langs->trans("Date").''.dol_print_date($object->date_trans, 'day').'
'.$langs->trans("Counterparty").''.dol_escape_htmltag($object->name).'
'.$langs->trans("AccountingAccount").''; + print $formaccounting->select_account(GETPOST('accountancy_code', 'alpha'), 'accountancy_code', 1, array(), 0, 0, 'minwidth200 maxwidth500', '', 1); + print '
'.$langs->trans("SubledgerAccount").''; + print $formaccounting->select_auxaccount(GETPOST('subledger_account', 'alpha'), 'subledger_account', 1, 'minwidth200 maxwidth500'); + print '
'.$langs->trans("DebitCredit").''; + $sensValue = GETPOSTISSET('sens') ? GETPOSTINT('sens') : $defaultSens; + print ''; + print '
'.$langs->trans("Label").''; + $labelValue = GETPOSTISSET('various_label') ? GETPOST('various_label', 'alphanohtml') : $defaultLabel; + print ''; + print '
'; + + print '
'; + print ''; + print '   '; + print ''.$langs->trans("Cancel").''; + print '
'; + + print '
'; + } + // Manual invoice selection (only for new transactions) if ($object->status == BankImportTransaction::STATUS_NEW) { // Determine if this is likely a supplier payment (negative amount) or customer (positive) diff --git a/class/banktransaction.class.php b/class/banktransaction.class.php index 96305a4..623107c 100755 --- a/class/banktransaction.class.php +++ b/class/banktransaction.class.php @@ -455,7 +455,9 @@ class BankImportTransaction extends CommonObject $sql .= " status = ".((int) $this->status).","; $sql .= " fk_user_modif = ".((int) $user->id).","; $sql .= " note_private = ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : "NULL").","; - $sql .= " note_public = ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : "NULL"); + $sql .= " note_public = ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : "NULL").","; + $sql .= " fk_user_match = ".($this->fk_user_match > 0 ? ((int) $this->fk_user_match) : "NULL").","; + $sql .= " date_match = ".($this->date_match ? "'".$this->db->idate($this->date_match)."'" : "NULL"); $sql .= " WHERE rowid = ".((int) $this->id); dol_syslog(get_class($this)."::update", LOG_DEBUG); @@ -1538,6 +1540,88 @@ class BankImportTransaction extends CommonObject return -4; } + /** + * Create a various payment (PaymentVarious) for this transaction + * Used for transactions without invoices (tax refunds, internal transfers, etc.) + * + * @param User $user User performing the action + * @param int $bankAccountId Dolibarr bank account ID + * @param string $accountancyCode Accounting account code (e.g. '1780') + * @param int $sens 0=debit, 1=credit + * @param string $label Payment label + * @param string $subledgerAccount Subledger account (optional) + * @param int $typePayment Payment type ID (0 = auto-detect VIR) + * @return int >0 if OK (PaymentVarious ID), <0 if error + */ + public function createVariousPayment($user, $bankAccountId, $accountancyCode, $sens, $label, $subledgerAccount = '', $typePayment = 0) + { + global $conf, $langs; + + $error = 0; + $this->db->begin(); + + // Look up payment type ID for 'VIR' (bank transfer) if not provided + if (empty($typePayment)) { + $sql = "SELECT id FROM ".MAIN_DB_PREFIX."c_paiement WHERE code = 'VIR' AND active = 1"; + $resql = $this->db->query($sql); + if ($resql && $this->db->num_rows($resql) > 0) { + $obj = $this->db->fetch_object($resql); + $typePayment = (int) $obj->id; + } + if (empty($typePayment)) { + $this->error = 'Payment type VIR not found in c_paiement'; + $this->db->rollback(); + return -1; + } + } + + require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php'; + + $various = new PaymentVarious($this->db); + $various->datep = $this->date_trans; + $various->datev = $this->date_value ?: $this->date_trans; + $various->sens = $sens; + $various->amount = abs($this->amount); + $various->type_payment = $typePayment; + $various->num_payment = $this->end_to_end_id ?: $this->ref; + $various->label = $label; + $various->accountancy_code = $accountancyCode; + $various->subledger_account = !empty($subledgerAccount) ? $subledgerAccount : ''; + $various->fk_account = $bankAccountId; + $various->note = $langs->trans("PaymentCreatedByBankImport").' - '.$this->name.' - '.dol_trunc($this->description, 100); + + $variousId = $various->create($user); + if ($variousId < 0) { + $this->error = $various->error; + $this->errors = $various->errors; + $error++; + } + + if (!$error) { + // Get the bank line ID created by PaymentVarious + $sql = "SELECT fk_bank FROM ".MAIN_DB_PREFIX."payment_various WHERE rowid = ".((int) $variousId); + $resql = $this->db->query($sql); + if ($resql && $this->db->num_rows($resql) > 0) { + $obj = $this->db->fetch_object($resql); + $this->fk_bank = (int) $obj->fk_bank; + } + + // Update transaction status to MATCHED + $this->status = self::STATUS_MATCHED; + $this->fk_user_match = $user->id; + $this->date_match = dol_now(); + $this->update($user); + } + + if ($error) { + $this->db->rollback(); + return -2; + } + + $this->db->commit(); + return $variousId; + } + /** * Confirm payment for multiple invoices (batch payment) * Creates a single payment that covers multiple invoices diff --git a/core/modules/modBankImport.class.php b/core/modules/modBankImport.class.php index 2d9f5b6..1f6e359 100755 --- a/core/modules/modBankImport.class.php +++ b/core/modules/modBankImport.class.php @@ -76,7 +76,7 @@ class modBankImport extends DolibarrModules $this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@bankimport' // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z' - $this->version = '3.5'; + $this->version = '3.7'; // Url to the file with your last numberversion of this module //$this->url_last_version = 'http://www.example.com/versionmodule.txt'; diff --git a/langs/de_DE/bankimport.lang b/langs/de_DE/bankimport.lang index d5e648d..46238df 100755 --- a/langs/de_DE/bankimport.lang +++ b/langs/de_DE/bankimport.lang @@ -404,3 +404,17 @@ StatementsNotPdfFormat = Kontoauszüge empfangen, aber nicht im PDF-Format StatementsUsingHKEKA = Nutze HKEKA (generischer Kontoauszug) statt HKEKP StatementsUsingHKEKP = Nutze HKEKP (PDF-Kontoauszug) NeitherHKEKPnorHKEKA = Die Bank unterstützt weder HKEKP noch HKEKA für elektronische Kontoauszüge + +# +# Sonstige Zahlung (PaymentVarious) +# +CreateVariousPayment = Zahlung anlegen +AccountingAccount = Buchungskonto +SubledgerAccount = Nebenbuchkonto +DebitCredit = Buchungsseite +Debit = Soll +Credit = Haben +Expense = Ausgabe +Income = Einnahme +VariousPaymentCreated = Sonstige Zahlung erfolgreich erstellt +VariousPayment = Sonstige Zahlung diff --git a/langs/en_US/bankimport.lang b/langs/en_US/bankimport.lang index 5d2a5c2..fa25362 100755 --- a/langs/en_US/bankimport.lang +++ b/langs/en_US/bankimport.lang @@ -301,3 +301,17 @@ StatementsUsingHKEKP = Using HKEKP (PDF statement) NeitherHKEKPnorHKEKA = The bank supports neither HKEKP nor HKEKA for electronic statements BankImportAutoFetch = Automatic bank import (transactions) BankImportFetchPdfStatements = Automatic PDF statement retrieval + +# +# Various Payment (PaymentVarious) +# +CreateVariousPayment = Create Payment +AccountingAccount = Accounting Account +SubledgerAccount = Subledger Account +DebitCredit = Debit/Credit +Debit = Debit +Credit = Credit +Expense = Expense +Income = Income +VariousPaymentCreated = Various payment created successfully +VariousPayment = Various Payment