Skip to content
Code-Schnipsel Gruppen Projekte
Commit 37c18b41 erstellt von Patrick Müller's avatar Patrick Müller
Dateien durchsuchen

feat: PaymentReceiver provider erp#41

Übergeordneter a6bad004
Keine zugehörigen Branchen gefunden
Keine zugehörigen Tags gefunden
Keine zugehörigen Merge Requests gefunden
<?php
use QUI\ERP\Accounting\Payments\Transactions\IncomingPayments\Handler;
use QUI\Utils\Security\Orthos;
use QUI\ERP\Accounting\Payments\Transactions\Exception;
/**
* Get data for new payment transaction
*
* @param string|int $entityId - Payment receiver entity ID
* @param string $entityType - Payment receiver entity type
* @return array
*
* @throws Exception
*/
QUI::$Ajax->registerFunction(
'package_quiqqer_payment-transactions_ajax_backend_IncomingPayments_getData',
function ($entityId, $entityType) {
$entityType = Orthos::clear($entityType);
$entityId = Orthos::clear($entityId);
$Provider = Handler::getPaymentReceiver($entityType, $entityId);
if (empty($Provider)) {
QUI\System\Log::addError(
'No paymentReceiver provider found for entity type: '.$entityType
);
throw new Exception([
'quiqqer/payment-transactions',
'exception.ajax.backend.IncomingPayments.getData.no_provider'
]);
}
$Locale = QUI::getLocale();
$Currency = $Provider->getCurrency();
$data = [
'debtorNo' => $Provider->getDebtorNo(),
'addressSalutation' => '',
'addressName' => '',
'addressStreet' => '',
'addressCity' => '',
'addressCountry' => '',
'documentType' => $Provider::getTypeTitle($Locale),
'documentNo' => $Provider->getDocumentNo(),
'date' => $Locale->formatDate($Provider->getDate()->getTimestamp()),
'dueDate' => $Provider->getDueDate() ?
$Locale->formatDate($Provider->getDueDate()->getTimestamp()) : '',
'amountTotal' => $Currency->format($Provider->getAmountTotal(), $Locale),
'amountPaid' => $Currency->format($Provider->getAmountPaid(), $Locale),
'amountOpen' => $Currency->format($Provider->getAmountOpen(), $Locale),
'amountOpenRaw' => $Provider->getAmountOpen(),
'paymentId' => $Provider->getPaymentMethod() ? $Provider->getPaymentMethod()->getId() : false
];
// Address
$Address = $Provider->getDebtorAddress();
if ($Address) {
$data['addressSalutation'] = $Address->getAttribute('salutation') ?: '';
$data['addressName'] = $Address->getName() ?: '';
$data['addressStreet'] = $Address->getAttribute('street_no') ?: '';
$data['addressCity'] = $Address->getAttribute('city') ?: '';
$data['addressCountry'] = $Address->getCountry() ? $Address->getCountry()->getName($Locale) : '';
}
return $data;
},
['entityId', 'entityType'],
'Permission::checkAdminUser'
);
.quiqqer-payment-transactions-add .data-table {
float: none !important;
height: 100%;
}
.quiqqer-payment-transactions-add .data-table .field-container-item {
width: 140px !important;
}
.quiqqer-payment-transactions-add-debtor,
.quiqqer-payment-transactions-add-document {
flex-grow: 1;
}
.quiqqer-payment-transactions-add-debtor {
margin: 0 20px 0 0;
}
.quiqqer-payment-transactions-add-payment {
margin: 20px 0 0 0;
}
.quiqqer-payment-transactions-add-data {
display: flex;
}
\ No newline at end of file
<div class="quiqqer-payment-transactions-add-data">
<div class="quiqqer-payment-transactions-add-debtor">
<table class="data-table data-table-flexbox">
<thead>
<tr>
<th>{{headerDebtor}}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelDebtorNo}}">
{{labelDebtorNo}}
</span>
<span class="field-container-field">
{{debtorNo}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelAddressSalutation}}">
{{labelAddressSalutation}}
</span>
<span class="field-container-field">
{{addressSalutation}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelAddressName}}">
{{labelAddressName}}
</span>
<span class="field-container-field">
{{addressName}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelAddressStreet}}">
{{labelAddressStreet}}
</span>
<span class="field-container-field">
{{addressStreet}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelAddressCity}}">
{{labelAddressCity}}
</span>
<span class="field-container-field">
{{addressCity}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelAddressCountry}}">
{{labelAddressCountry}}
</span>
<span class="field-container-field">
{{addressCountry}}
</span>
</label>
</td>
</tr>
</tbody>
</table>
</div>
<div class="quiqqer-payment-transactions-add-document">
<table class="data-table data-table-flexbox">
<thead>
<tr>
<th>{{headerDocument}}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelDocumentType}}">
{{labelDocumentType}}
</span>
<span class="field-container-field">
{{documentType}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelDocumentNo}}">
{{labelDocumentNo}}
</span>
<span class="field-container-field">
{{documentNo}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelDate}}">
{{labelDate}}
</span>
<span class="field-container-field">
{{date}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelDueDate}}">
{{labelDueDate}}
</span>
<span class="field-container-field">
{{dueDate}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelAmountTotal}}">
{{labelAmountTotal}}
</span>
<span class="field-container-field">
{{amountTotal}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelAmountPaid}}">
{{labelAmountPaid}}
</span>
<span class="field-container-field">
{{amountPaid}}
</span>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelAmountOpen}}">
{{labelAmountOpen}}
</span>
<span class="field-container-field">
{{amountOpen}}
</span>
</label>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="quiqqer-payment-transactions-add-payment">
<form>
<table class="data-table data-table-flexbox">
<thead>
<tr>
<th>{{headerPayment}}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelTransactionAmount}}">
{{labelTransactionAmount}}
</span>
<input class="field-container-field"
type="number"
name="amount"
step="0.01"
min="0"
autofocus
required
/>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelPayment}}">
{{labelPayment}}
</span>
<select class="field-container-field" name="payment_method" required>
</select>
</label>
</td>
</tr>
<tr>
<td>
<label class="field-container">
<span class="field-container-item" title="{{labelPaymentDate}}">
{{labelPaymentDate}}
</span>
<input class="field-container-field" type="date" name="date" required/>
</label>
</td>
</tr>
</tbody>
</table>
</form>
</div>
\ No newline at end of file
/**
* Add a payment to an ERP entity (e.g. invoice, offer...)
*
* @module package/quiqqer/payment-transactions/bin/backend/controls/IncomingPayments/AddPayment
* @author www.pcsg.de (Henning Leutz)
* @author www.pcsg.de (Patrick Müller)
*
* @event onLoad [self]
* @event onSubmit [TransactionData, self]
*/
define('package/quiqqer/payment-transactions/bin/backend/controls/IncomingPayments/AddPayment', [
'qui/controls/Control',
'qui/controls/loader/Loader',
'qui/utils/Form',
'Mustache',
'Locale',
'Ajax',
'package/quiqqer/payments/bin/backend/Payments',
'text!package/quiqqer/payment-transactions/bin/backend/controls/IncomingPayments/AddPayment.html',
'css!package/quiqqer/payment-transactions/bin/backend/controls/IncomingPayments/AddPayment.css'
], function (QUIControl, QUILoader, QUIFormUtils, Mustache, QUILocale, QUIAjax, Payments, template) {
"use strict";
var lg = 'quiqqer/payment-transactions';
return new Class({
Extends: QUIControl,
Type : 'package/quiqqer/payment-transactions/bin/backend/controls/IncomingPayments/AddPayment',
Binds: [
'$onInject',
'$getData'
],
options: {
entityId : false,
entityType: false
},
initialize: function (options) {
this.parent(options);
this.$Form = null;
this.Loader = new QUILoader();
this.addEvents({
onInject: this.$onInject
});
},
/**
* Create the DomNode Element
*
* @return {Element|null}
*/
create: function () {
this.$Elm = new Element('div', {
'class': 'quiqqer-payment-transactions-add'
});
this.Loader.inject(this.$Elm);
return this.$Elm;
},
/**
* event: on inject
*/
$onInject: function () {
Promise.all([
Payments.getPayments(),
this.$getData()
]).then(function (result) {
var title, payment;
var payments = result[0],
Data = result[1],
current = QUILocale.getCurrent();
// Build content
this.$Elm.set('html', Mustache.render(template, Object.merge({}, Data, {
labelDebtorNo : QUILocale.get(lg, 'controls.AddPayment.tpl.labelDebtorNo'),
labelAddressName : QUILocale.get('quiqqer/quiqqer', 'name'),
labelAddressStreet : QUILocale.get(lg, 'street'),
labelAddressCity : QUILocale.get(lg, 'city'),
labelAddressCountry : QUILocale.get(lg, 'country'),
labelAddressSalutation: QUILocale.get(lg, 'salutation'),
labelDocumentType : QUILocale.get(lg, 'controls.AddPayment.tpl.labelDocumentType'),
labelDocumentNo : QUILocale.get(lg, 'controls.AddPayment.tpl.labelDocumentNo'),
labelDate : QUILocale.get(lg, 'controls.AddPayment.tpl.labelDate'),
labelDueDate : QUILocale.get(lg, 'controls.AddPayment.tpl.labelDueDate'),
labelAmountTotal : QUILocale.get(lg, 'controls.AddPayment.tpl.labelAmountTotal'),
labelAmountPaid : QUILocale.get(lg, 'controls.AddPayment.tpl.labelAmountPaid'),
labelAmountOpen : QUILocale.get(lg, 'controls.AddPayment.tpl.labelAmountOpen'),
labelPayment : QUILocale.get(lg, 'controls.AddPayment.tpl.labelPayment'),
labelPaymentDate : QUILocale.get(lg, 'controls.AddPayment.tpl.labelPaymentDate'),
labelTransactionAmount: QUILocale.get(lg, 'controls.AddPayment.tpl.labelTransactionAmount'),
headerDebtor : QUILocale.get(lg, 'controls.AddPayment.tpl.headerDebtor'),
headerDocument : QUILocale.get(lg, 'controls.AddPayment.tpl.headerDocument'),
headerPayment : QUILocale.get(lg, 'controls.AddPayment.tpl.headerPayment')
})));
this.$Form = this.$Elm.getElement('form');
this.$Form.addEvent('submit', function (event) {
event.stop();
this.fireEvent('submit', [this.getValue(), this]);
}.bind(this));
var Payments = this.getElm().getElement('[name="payment_method"]');
var Amount = this.getElm().getElement('[name="amount"]');
this.getElm().getElement('[name="date"]').valueAsDate = new Date();
for (var i = 0, len = payments.length; i < len; i++) {
payment = payments[i];
title = payment.title;
if (typeOf(payment.title) === 'object' && current in payment.title) {
title = payment.title[current];
}
if (typeOf(payment.workingTitle) === 'object' &&
current in payment.workingTitle &&
payment.workingTitle[current] !== ''
) {
title = payment.workingTitle[current];
}
new Element('option', {
html : title,
value: parseInt(payment.id)
}).inject(Payments);
}
if (Data.paymentId) {
Payments.value = Data.paymentId;
}
if (Data.amountOpenRaw) {
Amount.value = Data.amountOpenRaw;
}
this.fireEvent('load', [this]);
}.bind(this));
},
/**
* Return the form data
*
* @return {Object}
*/
getValue: function () {
return QUIFormUtils.getFormData(this.$Form);
},
/**
* Focus the amount field
*/
focus: function () {
this.getElm().getElement('[name="amount"]').focus();
},
/**
* Get details for transactions
*
* @return {Promise}
*/
$getData: function () {
var self = this;
return new Promise(function (resolve, reject) {
QUIAjax.get('package_quiqqer_payment-transactions_ajax_backend_IncomingPayments_getData', resolve, {
'package' : 'quiqqer/payment-transactions',
entityId : self.getAttribute('entityId'),
entityType: self.getAttribute('entityType'),
onError : reject
});
});
}
});
});
\ No newline at end of file
/**
* Add a payment to an ERP entity (e.g. invoice, offer...)
*
* @module package/quiqqer/payment-transactions/bin/backend/controls/IncomingPayments/AddPaymentWindow
* @author www.pcsg.de (Henning Leutz)
* @author www.pcsg.de (Patrick Müller)
*/
define('package/quiqqer/payment-transactions/bin/backend/controls/IncomingPayments/AddPaymentWindow', [
'qui/controls/windows/Confirm',
'package/quiqqer/payment-transactions/bin/backend/controls/IncomingPayments/AddPayment',
'Locale'
], function (QUIConfirm, AddPayment, QUILocale) {
"use strict";
var lg = 'quiqqer/payment-transactions';
return new Class({
Extends: QUIConfirm,
Type : 'package/quiqqer/payment-transactions/bin/backend/controls/IncomingPayments/AddPayment',
Binds: [
'submit'
],
options: {
entityId : false,
entityType: false
},
initialize: function (options) {
this.setAttributes({
icon : 'fa fa-money',
title : QUILocale.get(lg, 'controls.AddPaymentWindow.title'),
maxHeight: 750,
maxWidth : 800
});
this.parent(options);
this.$AddPayment = null;
this.addEvents({
onOpen: this.$onOpen
});
},
/**
* event: on open
*/
$onOpen: function () {
this.Loader.show();
this.getContent().set('html', '');
this.$AddPayment = new AddPayment({
entityId : this.getAttribute('entityId'),
entityType: this.getAttribute('entityType'),
events : {
onLoad: function () {
this.Loader.hide();
this.$AddPayment.focus();
}.bind(this),
onSubmit: this.submit
}
}).inject(this.getContent());
},
/**
* Submit the window
*
* @return {Promise}
*/
submit: function () {
return new Promise(function (resolve) {
var values = this.$AddPayment.getValue();
if (values.amount === '') {
return;
}
if (values.payment_method === '') {
return;
}
this.fireEvent('submit', [this, values]);
resolve(values);
this.close();
}.bind(this));
}
});
});
......@@ -58,6 +58,44 @@
<de><![CDATA[Zahlung von [amount] - TX-ID: [txid]]]></de>
<en><![CDATA[Payment off [amount] - TX ID: [txid]]]></en>
</locale>
<locale name="address">
<de><![CDATA[Adresse]]></de>
<en><![CDATA[Address]]></en>
</locale>
<locale name="company">
<de><![CDATA[Firma]]></de>
<en><![CDATA[Company]]></en>
</locale>
<locale name="street">
<de><![CDATA[Straße]]></de>
<en><![CDATA[Street]]></en>
</locale>
<locale name="zip">
<de><![CDATA[PLZ]]></de>
<en><![CDATA[ZIP]]></en>
</locale>
<locale name="city">
<de><![CDATA[Ort]]></de>
<en><![CDATA[City]]></en>
</locale>
<locale name="country">
<de><![CDATA[Land]]></de>
<en><![CDATA[Country]]></en>
</locale>
<locale name="salutation">
<de><![CDATA[Anrede]]></de>
<en><![CDATA[Salutation]]></en>
</locale>
<locale name="firstname">
<de><![CDATA[Vorname]]></de>
<en><![CDATA[Firstname]]></en>
</locale>
<locale name="lastname">
<de><![CDATA[Nachname]]></de>
<en><![CDATA[Lastname]]></en>
</locale>
</groups>
<groups name="quiqqer/payment-transactions" datatype="js">
......@@ -138,6 +176,68 @@
<de><![CDATA[Für diese Zahlung kann keine Rückzahlung durchgeführt werden.]]></de>
<en><![CDATA[No refund can be made for this payment.]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelDebtorNo">
<de><![CDATA[Kunden-Nr.]]></de>
<en><![CDATA[Customer no.]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelDocumentNo">
<de><![CDATA[Beleg-Nr.]]></de>
<en><![CDATA[Document no.]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelDocumentType">
<de><![CDATA[Beleg-Typ]]></de>
<en><![CDATA[Document type]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelDate">
<de><![CDATA[Beleg-Datum]]></de>
<en><![CDATA[Document date]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelDueDate">
<de><![CDATA[Fälligkeit]]></de>
<en><![CDATA[Due date]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelAmountTotal">
<de><![CDATA[Summe]]></de>
<en><![CDATA[Sum]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelAmountPaid">
<de><![CDATA[bereits beglichen]]></de>
<en><![CDATA[already paid]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelAmountOpen">
<de><![CDATA[offen]]></de>
<en><![CDATA[open]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelPayment">
<de><![CDATA[Zahlungsmethode]]></de>
<en><![CDATA[Payment method]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelPaymentDate">
<de><![CDATA[Zahlungsdatum]]></de>
<en><![CDATA[Payment date]]></en>
</locale>
<locale name="controls.AddPayment.tpl.labelTransactionAmount">
<de><![CDATA[Eingehender Betrag]]></de>
<en><![CDATA[Incoming amount]]></en>
</locale>
<locale name="controls.AddPayment.tpl.headerDebtor">
<de><![CDATA[Kundendaten]]></de>
<en><![CDATA[Customer data]]></en>
</locale>
<locale name="controls.AddPayment.tpl.headerDocument">
<de><![CDATA[Beleg]]></de>
<en><![CDATA[Document]]></en>
</locale>
<locale name="controls.AddPayment.tpl.headerPayment">
<de><![CDATA[Eingehende Zahlung]]></de>
<en><![CDATA[Incoming payment]]></en>
</locale>
<locale name="controls.AddPaymentWindow.title">
<de><![CDATA[Zahlung buchen]]></de>
<en><![CDATA[Book payment]]></en>
</locale>
</groups>
<groups name="quiqqer/payment-transactions" datatype="php">
......@@ -182,5 +282,10 @@
We're sorry, but something went wrong. Please contact an administrator.
]]></en>
</locale>
<locale name="exception.ajax.backend.IncomingPayments.getData.no_provider">
<de><![CDATA[Für diesen Beleg-Typ kann z.Z. keine Transaktion erstellt werden. Bitte wenden Sie sich an einen Administrator.]]></de>
<en><![CDATA[No transaction can be created for this document type at the moment. Please contact an administrator.]]></en>
</locale>
</groups>
</locales>
<?php
namespace QUI\ERP\Accounting\Payments\Transactions\IncomingPayments;
use QUI;
/**
* Class Handler
*
* Handles incoming payment transaction provider
*/
class Handler
{
/**
* Get ERP payment receiver by entity type
*
* @param string $type
* @param string|int $id - Payment receiver entity ID
* @return PaymentReceiverInterface|false - PaymentReceiverInterface class or false if not found
*/
public static function getPaymentReceiver(string $type, $id)
{
$ProviderInstance = false;
/** @var PaymentReceiverInterface $Provider */
foreach (self::getAllPaymentReceiverProviders() as $Provider) {
if ($Provider::getType() === $type) {
$ProviderInstance = new $Provider($id);
break;
}
}
return $ProviderInstance;
}
/**
* Get all available ERP payment receiver providers
*
* @return string[] - Provider classes (static)
*/
public static function getAllPaymentReceiverProviders(): array
{
$packages = QUI::getPackageManager()->getInstalled();
$providerClasses = [];
foreach ($packages as $installedPackage) {
try {
$Package = QUI::getPackage($installedPackage['name']);
if (!$Package->isQuiqqerPackage()) {
continue;
}
$packageProvider = $Package->getProvider();
if (empty($packageProvider['paymentReceiver'])) {
continue;
}
/** @var PaymentReceiverInterface $class */
foreach ($packageProvider['paymentReceiver'] as $class) {
if (!\class_exists($class)) {
continue;
}
$providerClasses[] = $class;
}
} catch (QUI\Exception $Exception) {
QUI\System\Log::writeException($Exception);
}
}
return $providerClasses;
}
}
<?php
namespace QUI\ERP\Accounting\Payments\Transactions\IncomingPayments;
use QUI\ERP\Address;
use QUI\ERP\Accounting\Payments\Types\PaymentInterface;
use QUI\ERP\Currency\Currency;
use QUI\Locale;
/**
* Interface PaymentReceiverInterface
*
* Main interface for entities that can receive payments
*/
interface PaymentReceiverInterface
{
/**
* Get entity type descriptor
*
* @return string
*/
public static function getType(): string;
/**
* Get entity type title
*
* @param Locale $Locale (optional) - If omitted use \QUI::getLocale()
* @return string
*/
public static function getTypeTitle(Locale $Locale = null): string;
/**
* PaymentReceiverInterface constructor.
* @param string|int $id - Payment receiver entity ID
*/
public function __construct($id);
/**
* Get payment address of of the debtor (e.g. customer)
*
* @param string|int $id - Payment entity ID
* @return Address|false
*/
public function getDebtorAddress();
/**
* Get full document no
*
* @return string
*/
public function getDocumentNo(): string;
/**
* Get the unique recipient no. of the debtor (e.g. customer no.)
*
* @param string|int $id - Payment entity ID
* @return string
*/
public function getDebtorNo(): string;
public function getDate(): \DateTime;
/**
* Get entity due date (if applicable)
*
* @return \DateTime|false
*/
public function getDueDate();
public function getCurrency(): Currency;
public function getAmountTotal(): float;
public function getAmountOpen(): float;
public function getAmountPaid(): float;
/**
* Get payment method
*
* @return PaymentInterface|false
*/
public function getPaymentMethod();
}
0% Lade oder .
You are about to add 0 people to the discussion. Proceed with caution.
Bearbeitung dieser Nachricht zuerst beenden!
Bitte registrieren oder zum Kommentieren