First commit waiting for Budget Alert
This commit is contained in:
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.db.repo;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLineOrigin;
|
||||
import com.axelor.apps.tool.StringTool;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
|
||||
public class BankOrderLineManagementRepository extends BankOrderLineRepository {
|
||||
|
||||
@Override
|
||||
public Map<String, Object> populate(Map<String, Object> json, Map<String, Object> context) {
|
||||
Long bankOrderLineId = (Long) json.get("id");
|
||||
BankOrderLine bankOrderLine = find(bankOrderLineId);
|
||||
String pieceReferenceList = "";
|
||||
String pieceDateList = "";
|
||||
String pieceDueDateList = "";
|
||||
boolean bFirst = true;
|
||||
|
||||
for (BankOrderLineOrigin bankOrderLineOrigin : bankOrderLine.getBankOrderLineOriginList()) {
|
||||
if (bFirst) {
|
||||
pieceReferenceList += changeNullToEmptyString(bankOrderLineOrigin.getRelatedToSelectName());
|
||||
pieceDateList += changeDateToString(bankOrderLineOrigin.getRelatedToSelectDate());
|
||||
pieceDueDateList += changeDateToString(bankOrderLineOrigin.getRelatedToSelectDueDate());
|
||||
bFirst = false;
|
||||
} else {
|
||||
pieceReferenceList +=
|
||||
"," + changeNullToEmptyString(bankOrderLineOrigin.getRelatedToSelectName());
|
||||
pieceDateList += "," + changeDateToString(bankOrderLineOrigin.getRelatedToSelectDate());
|
||||
pieceDueDateList +=
|
||||
"," + changeDateToString(bankOrderLineOrigin.getRelatedToSelectDueDate());
|
||||
}
|
||||
}
|
||||
|
||||
json.put("$pieceReferenceList", StringTool.cutTooLongString(pieceReferenceList));
|
||||
json.put("$pieceDateList", StringTool.cutTooLongString(pieceDateList));
|
||||
json.put("$pieceDueDateList", StringTool.cutTooLongString(pieceDueDateList));
|
||||
|
||||
return super.populate(json, context);
|
||||
}
|
||||
|
||||
protected String changeNullToEmptyString(Object object) {
|
||||
if (object == null) {
|
||||
return "";
|
||||
} else {
|
||||
return object.toString();
|
||||
}
|
||||
}
|
||||
|
||||
protected String changeDateToString(LocalDate date) {
|
||||
if (date == null) {
|
||||
return "";
|
||||
} else {
|
||||
return date.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.db.repo;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
public class BankOrderManagementRepository extends BankOrderRepository {
|
||||
|
||||
@Override
|
||||
public BankOrder save(BankOrder entity) {
|
||||
|
||||
try {
|
||||
|
||||
BankOrderService bankOrderService = Beans.get(BankOrderService.class);
|
||||
bankOrderService.generateSequence(entity);
|
||||
bankOrderService.setSequenceOnBankOrderLines(entity);
|
||||
if (entity.getStatusSelect() == BankOrderRepository.STATUS_DRAFT) {
|
||||
bankOrderService.updateTotalAmounts(entity);
|
||||
}
|
||||
|
||||
return super.save(entity);
|
||||
} catch (Exception e) {
|
||||
throw new PersistenceException(e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BankOrder copy(BankOrder entity, boolean deep) {
|
||||
|
||||
BankOrder copy = super.copy(entity, deep);
|
||||
|
||||
copy.setStatusSelect(STATUS_DRAFT);
|
||||
copy.setGeneratedMetaFile(null);
|
||||
copy.setSignedMetaFile(null);
|
||||
copy.setConfirmationDateTime(null);
|
||||
copy.setFileGenerationDateTime(null);
|
||||
copy.setValidationDateTime(null);
|
||||
copy.setSendingDateTime(null);
|
||||
copy.setBankOrderSeq(null);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(BankOrder entity) {
|
||||
if (entity.getStatusSelect() == BankOrderRepository.STATUS_DRAFT
|
||||
|| entity.getStatusSelect() == BankOrderRepository.STATUS_CANCELED) {
|
||||
super.remove(entity);
|
||||
return;
|
||||
}
|
||||
throw new PersistenceException(I18n.get(IExceptionMessage.BANK_ORDER_CANNOT_REMOVE));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.db.repo;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankReconciliation;
|
||||
import com.axelor.apps.bankpayment.service.bankreconciliation.BankReconciliationCreateService;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.common.base.Strings;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class BankReconciliationManagementRepository extends BankReconciliationRepository {
|
||||
@Override
|
||||
public BankReconciliation copy(BankReconciliation entity, boolean deep) {
|
||||
entity.setStatusSelect(STATUS_DRAFT);
|
||||
entity.setStartingBalance(BigDecimal.ZERO);
|
||||
entity.setEndingBalance(BigDecimal.ZERO);
|
||||
entity.setComputedBalance(BigDecimal.ZERO);
|
||||
entity.setAccountBalance(BigDecimal.ZERO);
|
||||
entity.setTotalCashed(BigDecimal.ZERO);
|
||||
entity.setTotalPaid(BigDecimal.ZERO);
|
||||
entity.setBankReconciliationLineList(null);
|
||||
|
||||
return super.copy(entity, deep);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BankReconciliation save(BankReconciliation entity) {
|
||||
|
||||
if (Strings.isNullOrEmpty(entity.getName())) {
|
||||
entity.setName(Beans.get(BankReconciliationCreateService.class).computeName(entity));
|
||||
}
|
||||
|
||||
return super.save(entity);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.db.repo;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsBank;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsBankService;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class EbicsBankAccountRepository extends EbicsBankRepository {
|
||||
|
||||
@Inject EbicsBankService ebicsBankService;
|
||||
|
||||
@Override
|
||||
public EbicsBank save(EbicsBank ebicsBank) {
|
||||
ebicsBankService.computeFullName(ebicsBank);
|
||||
|
||||
return super.save(ebicsBank);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.db.repo;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsCertificate;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsCertificateService;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class EbicsCertificateAccountRepository extends EbicsCertificateRepository {
|
||||
|
||||
@Inject private EbicsCertificateService certificateService;
|
||||
|
||||
@Override
|
||||
public EbicsCertificate save(EbicsCertificate entity) {
|
||||
|
||||
certificateService.computeFullName(entity);
|
||||
|
||||
return super.save(entity);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.db.repo;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsRequestLog;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.util.List;
|
||||
|
||||
public class EbicsUserManagementRepository extends EbicsUserRepository {
|
||||
|
||||
@Override
|
||||
public void remove(EbicsUser entity) {
|
||||
EbicsRequestLogRepository ebicsRequestLogRepository =
|
||||
Beans.get(EbicsRequestLogRepository.class);
|
||||
List<EbicsRequestLog> ebicsRequestLogList =
|
||||
ebicsRequestLogRepository.all().filter("self.ebicsUser = ?1", entity).fetch();
|
||||
for (EbicsRequestLog ebicsRequestLog : ebicsRequestLogList) {
|
||||
ebicsRequestLogRepository.remove(ebicsRequestLog);
|
||||
}
|
||||
super.remove(entity);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.db.repo;
|
||||
|
||||
import com.axelor.apps.account.db.Move;
|
||||
import com.axelor.apps.account.db.MoveLine;
|
||||
import com.axelor.apps.account.db.repo.MoveManagementRepository;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
public class MoveBankPaymentRepository extends MoveManagementRepository {
|
||||
|
||||
@Override
|
||||
public Move copy(Move entity, boolean deep) {
|
||||
Move copy = super.copy(entity, deep);
|
||||
|
||||
List<MoveLine> moveLineList = copy.getMoveLineList();
|
||||
|
||||
if (moveLineList != null) {
|
||||
moveLineList.forEach(moveLine -> moveLine.setBankReconciledAmount(BigDecimal.ZERO));
|
||||
}
|
||||
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.certificate;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsCertificate;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsCertificateRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsPartnerRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsUserRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsCertificateService;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyStore;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
/**
|
||||
* Simple manager for EBICS certificates.
|
||||
*
|
||||
* @author hacheni
|
||||
*/
|
||||
public class CertificateManager {
|
||||
|
||||
public CertificateManager(EbicsUser user) {
|
||||
this.user = user;
|
||||
generator = new X509Generator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the certificates for the user
|
||||
*
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void create() throws GeneralSecurityException, IOException {
|
||||
|
||||
Calendar calendar;
|
||||
|
||||
calendar = Calendar.getInstance();
|
||||
calendar.add(
|
||||
Calendar.YEAR, user.getEbicsPartner().getEbicsBank().getCertValidityPeriodSelect());
|
||||
|
||||
org.apache.xml.security.Init.init();
|
||||
java.security.Security.addProvider(new BouncyCastleProvider());
|
||||
|
||||
EbicsPartner ebicsPartner = user.getEbicsPartner();
|
||||
|
||||
if ((user.getUserTypeSelect() == EbicsUserRepository.USER_TYPE_TRANSPORT
|
||||
&& ebicsPartner.getEbicsTypeSelect() == EbicsPartnerRepository.EBICS_TYPE_TS)
|
||||
|| ebicsPartner.getEbicsTypeSelect() == EbicsPartnerRepository.EBICS_TYPE_T) {
|
||||
createA005Certificate(new Date(calendar.getTimeInMillis()));
|
||||
}
|
||||
createX002Certificate(new Date(calendar.getTimeInMillis()));
|
||||
createE002Certificate(new Date(calendar.getTimeInMillis()));
|
||||
setUserCertificates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the user certificates
|
||||
*
|
||||
* @throws IOException
|
||||
* @throws CertificateEncodingException
|
||||
*/
|
||||
private void setUserCertificates() throws IOException, CertificateEncodingException {
|
||||
|
||||
EbicsPartner ebicsPartner = user.getEbicsPartner();
|
||||
|
||||
if ((user.getUserTypeSelect() == EbicsUserRepository.USER_TYPE_TRANSPORT
|
||||
&& ebicsPartner.getEbicsTypeSelect() == EbicsPartnerRepository.EBICS_TYPE_TS)
|
||||
|| ebicsPartner.getEbicsTypeSelect() == EbicsPartnerRepository.EBICS_TYPE_T) {
|
||||
user.setA005Certificate(
|
||||
updateCertificate(
|
||||
a005Certificate,
|
||||
user.getA005Certificate(),
|
||||
a005PrivateKey.getEncoded(),
|
||||
EbicsCertificateRepository.TYPE_SIGNATURE));
|
||||
}
|
||||
|
||||
user.setX002Certificate(
|
||||
updateCertificate(
|
||||
x002Certificate,
|
||||
user.getX002Certificate(),
|
||||
x002PrivateKey.getEncoded(),
|
||||
EbicsCertificateRepository.TYPE_AUTHENTICATION));
|
||||
|
||||
user.setE002Certificate(
|
||||
updateCertificate(
|
||||
e002Certificate,
|
||||
user.getE002Certificate(),
|
||||
e002PrivateKey.getEncoded(),
|
||||
EbicsCertificateRepository.TYPE_ENCRYPTION));
|
||||
}
|
||||
|
||||
private EbicsCertificate updateCertificate(
|
||||
X509Certificate certificate, EbicsCertificate cert, byte[] privateKey, String type)
|
||||
throws CertificateEncodingException, IOException {
|
||||
|
||||
if (cert == null) {
|
||||
cert = new EbicsCertificate();
|
||||
cert.setTypeSelect(type);
|
||||
}
|
||||
|
||||
EbicsCertificateService certificateService = Beans.get(EbicsCertificateService.class);
|
||||
|
||||
cert = certificateService.updateCertificate(certificate, cert, true);
|
||||
|
||||
cert.setPrivateKey(privateKey);
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the signature certificate.
|
||||
*
|
||||
* @param the expiration date of a the certificate.
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createA005Certificate(Date end) throws GeneralSecurityException, IOException {
|
||||
KeyPair keypair;
|
||||
|
||||
keypair = KeyUtil.makeKeyPair(X509Constants.EBICS_KEY_SIZE);
|
||||
a005Certificate =
|
||||
generator.generateA005Certificate(
|
||||
keypair,
|
||||
user.getDn(),
|
||||
new Date(),
|
||||
end,
|
||||
user.getEbicsPartner().getEbicsBank().getUseX509ExtentionForAutoSignedCert());
|
||||
a005PrivateKey = keypair.getPrivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the authentication certificate.
|
||||
*
|
||||
* @param the expiration date of a the certificate.
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createX002Certificate(Date end) throws GeneralSecurityException, IOException {
|
||||
KeyPair keypair;
|
||||
|
||||
keypair = KeyUtil.makeKeyPair(X509Constants.EBICS_KEY_SIZE);
|
||||
x002Certificate =
|
||||
generator.generateX002Certificate(
|
||||
keypair,
|
||||
user.getDn(),
|
||||
new Date(),
|
||||
end,
|
||||
user.getEbicsPartner().getEbicsBank().getUseX509ExtentionForAutoSignedCert());
|
||||
x002PrivateKey = keypair.getPrivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the encryption certificate.
|
||||
*
|
||||
* @param the expiration date of a the certificate.
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createE002Certificate(Date end) throws GeneralSecurityException, IOException {
|
||||
KeyPair keypair;
|
||||
|
||||
keypair = KeyUtil.makeKeyPair(X509Constants.EBICS_KEY_SIZE);
|
||||
e002Certificate =
|
||||
generator.generateE002Certificate(
|
||||
keypair,
|
||||
user.getDn(),
|
||||
new Date(),
|
||||
end,
|
||||
user.getEbicsPartner().getEbicsBank().getUseX509ExtentionForAutoSignedCert());
|
||||
e002PrivateKey = keypair.getPrivate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the certificates in PKCS12 format
|
||||
*
|
||||
* @param path the certificates path
|
||||
* @param pwdCallBack the password call back
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void save(String path) throws GeneralSecurityException, IOException {
|
||||
char[] pwd = null;
|
||||
if (user.getPassword() != null) {
|
||||
pwd = user.getPassword().toCharArray();
|
||||
}
|
||||
writePKCS12Certificate(path + "/" + user.getUserId(), pwd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads user certificates from a given key store
|
||||
*
|
||||
* @param path the key store path
|
||||
* @param pwdCallBack the password call back
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void load(String path) throws GeneralSecurityException, IOException {
|
||||
KeyStoreManager loader;
|
||||
|
||||
loader = new KeyStoreManager();
|
||||
|
||||
if (user.getPassword() != null) {
|
||||
loader.load(path, user.getPassword().toCharArray());
|
||||
} else {
|
||||
loader.load(path, null);
|
||||
}
|
||||
|
||||
a005Certificate = loader.getCertificate(user.getUserId() + "-A005");
|
||||
x002Certificate = loader.getCertificate(user.getUserId() + "-X002");
|
||||
e002Certificate = loader.getCertificate(user.getUserId() + "-E002");
|
||||
|
||||
a005PrivateKey = loader.getPrivateKey(user.getUserId() + "-A005");
|
||||
x002PrivateKey = loader.getPrivateKey(user.getUserId() + "-X002");
|
||||
e002PrivateKey = loader.getPrivateKey(user.getUserId() + "-E002");
|
||||
setUserCertificates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a the generated certificates into a PKCS12 key store.
|
||||
*
|
||||
* @param filename the key store file name
|
||||
* @param password the key password
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writePKCS12Certificate(String filename, char[] password)
|
||||
throws GeneralSecurityException, IOException {
|
||||
if (filename == null || "".equals(filename)) {
|
||||
throw new IOException("The file name cannot be empty");
|
||||
}
|
||||
|
||||
if (!filename.toLowerCase().endsWith(".p12")) {
|
||||
filename += ".p12";
|
||||
}
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(filename);
|
||||
writePKCS12Certificate(password, fos);
|
||||
fos.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a the generated certificates into a PKCS12 key store.
|
||||
*
|
||||
* @param password the key store password
|
||||
* @param fos the output stream
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writePKCS12Certificate(char[] password, OutputStream fos)
|
||||
throws GeneralSecurityException, IOException {
|
||||
KeyStore keystore;
|
||||
|
||||
keystore = KeyStore.getInstance("PKCS12", new BouncyCastleProvider());
|
||||
keystore.load(null, null);
|
||||
keystore.setKeyEntry(
|
||||
user.getUserId() + "-A005",
|
||||
a005PrivateKey,
|
||||
password,
|
||||
new X509Certificate[] {a005Certificate});
|
||||
keystore.setKeyEntry(
|
||||
user.getUserId() + "-X002",
|
||||
x002PrivateKey,
|
||||
password,
|
||||
new X509Certificate[] {x002Certificate});
|
||||
keystore.setKeyEntry(
|
||||
user.getUserId() + "-E002",
|
||||
e002PrivateKey,
|
||||
password,
|
||||
new X509Certificate[] {e002Certificate});
|
||||
keystore.store(fos, password);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private X509Generator generator;
|
||||
private EbicsUser user;
|
||||
|
||||
private X509Certificate a005Certificate;
|
||||
private X509Certificate e002Certificate;
|
||||
private X509Certificate x002Certificate;
|
||||
|
||||
private PrivateKey a005PrivateKey;
|
||||
private PrivateKey x002PrivateKey;
|
||||
private PrivateKey e002PrivateKey;
|
||||
}
|
||||
@ -0,0 +1,218 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.certificate;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.PrivateKey;
|
||||
import java.security.Provider;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
|
||||
/**
|
||||
* Key store loader. This class loads a key store from a given path and allow to get private keys
|
||||
* and certificates for a given alias. The PKCS12 key store type is recommended to be used
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class KeyStoreManager {
|
||||
|
||||
/**
|
||||
* Loads a certificate for a given alias
|
||||
*
|
||||
* @param alias the certificate alias
|
||||
* @return the certificate
|
||||
* @throws KeyStoreException
|
||||
*/
|
||||
public final X509Certificate getCertificate(String alias) throws KeyStoreException {
|
||||
X509Certificate cert;
|
||||
|
||||
cert = (X509Certificate) keyStore.getCertificate(alias);
|
||||
|
||||
if (cert == null) {
|
||||
throw new IllegalArgumentException("alias " + alias + " not found in the KeyStore");
|
||||
}
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a private key for a given alias
|
||||
*
|
||||
* @param alias the certificate alias
|
||||
* @return the private key
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
public final PrivateKey getPrivateKey(String alias) throws GeneralSecurityException {
|
||||
PrivateKey key;
|
||||
|
||||
key = (PrivateKey) keyStore.getKey(alias, password);
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("private key not found for alias " + alias);
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a key store from a given path and password
|
||||
*
|
||||
* @param path the key store path
|
||||
* @param password the key store password
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void load(String path, char[] password) throws GeneralSecurityException, IOException {
|
||||
keyStore = KeyStore.getInstance("PKCS12", "BC");
|
||||
this.password = password;
|
||||
load(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a key store and cache the loaded one
|
||||
*
|
||||
* @param path the key store path.
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
private void load(String path) throws GeneralSecurityException, IOException {
|
||||
if (path.equals("")) {
|
||||
this.keyStore.load(null, null);
|
||||
} else {
|
||||
this.keyStore.load(new FileInputStream(path), password);
|
||||
this.certs = read(this.keyStore);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a certificate from an input stream for a given provider
|
||||
*
|
||||
* @param input the input stream
|
||||
* @param provider the certificate provider
|
||||
* @return the certificate
|
||||
* @throws CertificateException
|
||||
* @throws IOException
|
||||
*/
|
||||
public X509Certificate read(InputStream input, Provider provider)
|
||||
throws CertificateException, IOException {
|
||||
X509Certificate certificate;
|
||||
|
||||
certificate =
|
||||
(X509Certificate)
|
||||
CertificateFactory.getInstance("X.509", provider).generateCertificate(input);
|
||||
|
||||
if (certificate == null) {
|
||||
try (final PEMParser reader = new PEMParser(new InputStreamReader(input))) {
|
||||
final X509CertificateHolder certificateHolder = (X509CertificateHolder) reader.readObject();
|
||||
certificate = new JcaX509CertificateConverter().getCertificate(certificateHolder);
|
||||
}
|
||||
}
|
||||
|
||||
return certificate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key of a given certificate.
|
||||
*
|
||||
* @param input the given certificate
|
||||
* @return The RSA public key of the given certificate
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public RSAPublicKey getPublicKey(InputStream input) throws GeneralSecurityException, IOException {
|
||||
X509Certificate cert;
|
||||
cert = read(input, keyStore.getProvider());
|
||||
return (RSAPublicKey) cert.getPublicKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the given certificate into the key store.
|
||||
*
|
||||
* @param alias the certificate alias
|
||||
* @param input the given certificate.
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public void setCertificateEntry(String alias, InputStream input)
|
||||
throws GeneralSecurityException, IOException {
|
||||
keyStore.setCertificateEntry(alias, read(input, keyStore.getProvider()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the key store to a given output stream.
|
||||
*
|
||||
* @param output the output stream.
|
||||
*/
|
||||
public void save(OutputStream output) throws GeneralSecurityException, IOException {
|
||||
keyStore.store(output, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificates contained in the key store.
|
||||
*
|
||||
* @return the certificates contained in the key store.
|
||||
*/
|
||||
public Map<String, X509Certificate> getCertificates() {
|
||||
return certs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all certificate existing in a given key store
|
||||
*
|
||||
* @param keyStore the key store
|
||||
* @return A <code>Map</code> of certificate, the key of the map is the certificate alias
|
||||
* @throws KeyStoreException
|
||||
*/
|
||||
public Map<String, X509Certificate> read(KeyStore keyStore) throws KeyStoreException {
|
||||
Map<String, X509Certificate> certificates;
|
||||
Enumeration<String> enumeration;
|
||||
|
||||
certificates = new HashMap<String, X509Certificate>();
|
||||
enumeration = keyStore.aliases();
|
||||
while (enumeration.hasMoreElements()) {
|
||||
String alias;
|
||||
|
||||
alias = enumeration.nextElement();
|
||||
certificates.put(alias, (X509Certificate) keyStore.getCertificate(alias));
|
||||
}
|
||||
|
||||
return certificates;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private KeyStore keyStore;
|
||||
private char[] password;
|
||||
private Map<String, X509Certificate> certs;
|
||||
}
|
||||
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.certificate;
|
||||
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
|
||||
/**
|
||||
* Some key utilities
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class KeyUtil {
|
||||
|
||||
/**
|
||||
* Generates a <code>KeyPair</code> in RSA format.
|
||||
*
|
||||
* @param keyLen - key size
|
||||
* @return KeyPair the key pair
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
public static KeyPair makeKeyPair(int keyLen) throws NoSuchAlgorithmException {
|
||||
KeyPairGenerator keyGen;
|
||||
|
||||
keyGen = KeyPairGenerator.getInstance("RSA");
|
||||
keyGen.initialize(keyLen, new SecureRandom());
|
||||
|
||||
KeyPair keypair = keyGen.generateKeyPair();
|
||||
|
||||
return keypair;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random password
|
||||
*
|
||||
* @return the password
|
||||
*/
|
||||
public static String generatePassword() {
|
||||
SecureRandom random;
|
||||
|
||||
try {
|
||||
random = SecureRandom.getInstance("SHA1PRNG");
|
||||
String pwd = Base64.encodeBase64String(random.generateSeed(5));
|
||||
|
||||
return pwd.substring(0, pwd.length() - 2);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return "changeit";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the digest value of a given public key.
|
||||
*
|
||||
* <p>In Version “H003” of the EBICS protocol the ES of the financial:
|
||||
*
|
||||
* <p>The SHA-256 hash values of the financial institution's public keys for X002 and E002 are
|
||||
* composed by concatenating the exponent with a blank character and the modulus in hexadecimal
|
||||
* representation (using lower case letters) without leading zero (as to the hexadecimal
|
||||
* representation). The resulting string has to be converted into a byte array based on US ASCII
|
||||
* code.
|
||||
*
|
||||
* @param publicKey the public key
|
||||
* @return the digest value
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public static byte[] getKeyDigest(RSAPublicKey publicKey) throws AxelorException {
|
||||
String modulus;
|
||||
String exponent;
|
||||
String hash;
|
||||
byte[] digest;
|
||||
|
||||
exponent = Hex.encodeHexString(publicKey.getPublicExponent().toByteArray());
|
||||
modulus = Hex.encodeHexString(removeFirstByte(publicKey.getModulus().toByteArray()));
|
||||
hash = exponent + " " + modulus;
|
||||
|
||||
if (hash.charAt(0) == '0') {
|
||||
hash = hash.substring(1);
|
||||
}
|
||||
|
||||
try {
|
||||
digest = MessageDigest.getInstance("SHA-256", "BC").digest(hash.getBytes("US-ASCII"));
|
||||
} catch (GeneralSecurityException | UnsupportedEncodingException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
|
||||
return new String(Hex.encodeHex(digest, false)).getBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the first byte of an byte array
|
||||
*
|
||||
* @return the array
|
||||
*/
|
||||
private static byte[] removeFirstByte(byte[] byteArray) {
|
||||
byte[] b = new byte[byteArray.length - 1];
|
||||
System.arraycopy(byteArray, 1, b, 0, b.length);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.certificate;
|
||||
|
||||
/**
|
||||
* X509 certificate constants
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public interface X509Constants {
|
||||
|
||||
/** Certificates key usage */
|
||||
int SIGNATURE_KEY_USAGE = 1;
|
||||
|
||||
int AUTHENTICATION_KEY_USAGE = 2;
|
||||
int ENCRYPTION_KEY_USAGE = 3;
|
||||
|
||||
/** Certificate signature algorithm */
|
||||
String SIGNATURE_ALGORITHM = "SHA256WithRSAEncryption";
|
||||
|
||||
/** EBICS key size */
|
||||
int EBICS_KEY_SIZE = 2048;
|
||||
}
|
||||
@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.certificate;
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990-2012 kopiLeft Development SARL, Bizerte, Tunisia
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.TimeZone;
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1InputStream;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.x509.AuthorityKeyIdentifier;
|
||||
import org.bouncycastle.asn1.x509.BasicConstraints;
|
||||
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
|
||||
import org.bouncycastle.asn1.x509.GeneralName;
|
||||
import org.bouncycastle.asn1.x509.GeneralNames;
|
||||
import org.bouncycastle.asn1.x509.KeyPurposeId;
|
||||
import org.bouncycastle.asn1.x509.KeyUsage;
|
||||
import org.bouncycastle.asn1.x509.SubjectKeyIdentifier;
|
||||
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
|
||||
import org.bouncycastle.asn1.x509.X509Extensions;
|
||||
import org.bouncycastle.asn1.x509.X509Name;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
|
||||
import org.bouncycastle.jce.X509Principal;
|
||||
import org.bouncycastle.x509.X509V3CertificateGenerator;
|
||||
|
||||
/**
|
||||
* An X509 certificate generator for EBICS protocol. Generated certificates are self signed
|
||||
* certificates.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class X509Generator {
|
||||
|
||||
/**
|
||||
* Generates the signature certificate for the EBICS protocol
|
||||
*
|
||||
* @param keypair the key pair
|
||||
* @param issuer the certificate issuer
|
||||
* @param notBefore the begin validity date
|
||||
* @param notAfter the end validity date
|
||||
* @return the signature certificate
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public X509Certificate generateA005Certificate(
|
||||
KeyPair keypair,
|
||||
String issuer,
|
||||
Date notBefore,
|
||||
Date notAfter,
|
||||
boolean useX509ExtentionForAutoSignedCert)
|
||||
throws GeneralSecurityException, IOException {
|
||||
return generate(
|
||||
keypair,
|
||||
issuer,
|
||||
notBefore,
|
||||
notAfter,
|
||||
X509Constants.SIGNATURE_KEY_USAGE,
|
||||
useX509ExtentionForAutoSignedCert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the authentication certificate for the EBICS protocol
|
||||
*
|
||||
* @param keypair the key pair
|
||||
* @param issuer the certificate issuer
|
||||
* @param notBefore the begin validity date
|
||||
* @param notAfter the end validity date
|
||||
* @return the authentication certificate
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public X509Certificate generateX002Certificate(
|
||||
KeyPair keypair,
|
||||
String issuer,
|
||||
Date notBefore,
|
||||
Date notAfter,
|
||||
boolean useX509ExtentionForAutoSignedCert)
|
||||
throws GeneralSecurityException, IOException {
|
||||
return generate(
|
||||
keypair,
|
||||
issuer,
|
||||
notBefore,
|
||||
notAfter,
|
||||
X509Constants.AUTHENTICATION_KEY_USAGE,
|
||||
useX509ExtentionForAutoSignedCert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the encryption certificate for the EBICS protocol
|
||||
*
|
||||
* @param keypair the key pair
|
||||
* @param issuer the certificate issuer
|
||||
* @param notBefore the begin validity date
|
||||
* @param notAfter the end validity date
|
||||
* @return the encryption certificate
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public X509Certificate generateE002Certificate(
|
||||
KeyPair keypair,
|
||||
String issuer,
|
||||
Date notBefore,
|
||||
Date notAfter,
|
||||
boolean useX509ExtentionForAutoSignedCert)
|
||||
throws GeneralSecurityException, IOException {
|
||||
return generate(
|
||||
keypair,
|
||||
issuer,
|
||||
notBefore,
|
||||
notAfter,
|
||||
X509Constants.ENCRYPTION_KEY_USAGE,
|
||||
useX509ExtentionForAutoSignedCert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <code>X509Certificate</code> from a given <code>KeyPair</code> and limit dates
|
||||
* validations
|
||||
*
|
||||
* @param keypair the given key pair
|
||||
* @param issuer the certificate issuer
|
||||
* @param notBefore the begin validity date
|
||||
* @param notAfter the end validity date
|
||||
* @param keyusage the certificate key usage
|
||||
* @return the X509 certificate
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
public X509Certificate generate(
|
||||
KeyPair keypair,
|
||||
String issuer,
|
||||
Date notBefore,
|
||||
Date notAfter,
|
||||
int keyusage,
|
||||
boolean useX509ExtentionForAutoSignedCert)
|
||||
throws GeneralSecurityException, IOException {
|
||||
X509V3CertificateGenerator generator;
|
||||
BigInteger serial;
|
||||
X509Certificate certificate;
|
||||
ASN1EncodableVector vector;
|
||||
|
||||
serial = BigInteger.valueOf(generateSerial());
|
||||
generator = new X509V3CertificateGenerator();
|
||||
generator.setSerialNumber(serial);
|
||||
generator.setIssuerDN(new X509Principal(issuer));
|
||||
generator.setNotBefore(notBefore);
|
||||
generator.setNotAfter(notAfter);
|
||||
generator.setSubjectDN(new X509Principal(issuer));
|
||||
generator.setPublicKey(keypair.getPublic());
|
||||
generator.setSignatureAlgorithm(X509Constants.SIGNATURE_ALGORITHM);
|
||||
|
||||
if (useX509ExtentionForAutoSignedCert) {
|
||||
generator.addExtension(X509Extensions.BasicConstraints, false, new BasicConstraints(true));
|
||||
generator.addExtension(
|
||||
X509Extensions.SubjectKeyIdentifier, false, getSubjectKeyIdentifier(keypair.getPublic()));
|
||||
generator.addExtension(
|
||||
X509Extensions.AuthorityKeyIdentifier,
|
||||
false,
|
||||
getAuthorityKeyIdentifier(keypair.getPublic(), issuer, serial));
|
||||
|
||||
vector = new ASN1EncodableVector();
|
||||
vector.add(KeyPurposeId.id_kp_emailProtection);
|
||||
|
||||
generator.addExtension(
|
||||
X509Extensions.ExtendedKeyUsage,
|
||||
false,
|
||||
ExtendedKeyUsage.getInstance(new DERSequence(vector)));
|
||||
}
|
||||
|
||||
switch (keyusage) {
|
||||
case X509Constants.SIGNATURE_KEY_USAGE:
|
||||
generator.addExtension(
|
||||
X509Extensions.KeyUsage, false, new KeyUsage(KeyUsage.nonRepudiation));
|
||||
break;
|
||||
case X509Constants.AUTHENTICATION_KEY_USAGE:
|
||||
generator.addExtension(
|
||||
X509Extensions.KeyUsage, false, new KeyUsage(KeyUsage.digitalSignature));
|
||||
break;
|
||||
case X509Constants.ENCRYPTION_KEY_USAGE:
|
||||
generator.addExtension(X509Extensions.KeyUsage, false, new KeyUsage(KeyUsage.keyAgreement));
|
||||
break;
|
||||
default:
|
||||
generator.addExtension(
|
||||
X509Extensions.KeyUsage,
|
||||
false,
|
||||
new KeyUsage(KeyUsage.keyEncipherment | KeyUsage.digitalSignature));
|
||||
break;
|
||||
}
|
||||
|
||||
certificate = generator.generate(keypair.getPrivate(), "BC", new SecureRandom());
|
||||
certificate.checkValidity(new Date());
|
||||
certificate.verify(keypair.getPublic());
|
||||
|
||||
return certificate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>AuthorityKeyIdentifier</code> corresponding to a given <code>PublicKey</code>
|
||||
*
|
||||
* @param publicKey the given public key
|
||||
* @param issuer the certificate issuer
|
||||
* @param serial the certificate serial number
|
||||
* @return the authority key identifier of the public key
|
||||
* @throws IOException
|
||||
*/
|
||||
private AuthorityKeyIdentifier getAuthorityKeyIdentifier(
|
||||
PublicKey publicKey, String issuer, BigInteger serial) throws IOException {
|
||||
|
||||
InputStream input;
|
||||
SubjectPublicKeyInfo keyInfo;
|
||||
ASN1EncodableVector vector;
|
||||
|
||||
input = new ByteArrayInputStream(publicKey.getEncoded());
|
||||
try (final ASN1InputStream is = new ASN1InputStream(input)) {
|
||||
keyInfo = SubjectPublicKeyInfo.getInstance((ASN1Sequence) is.readObject());
|
||||
}
|
||||
vector = new ASN1EncodableVector();
|
||||
vector.add(new GeneralName(new X509Name(issuer)));
|
||||
|
||||
return new AuthorityKeyIdentifier(
|
||||
keyInfo, GeneralNames.getInstance(new DERSequence(vector)), serial);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>SubjectKeyIdentifier</code> corresponding to a given <code>PublicKey</code>
|
||||
*
|
||||
* @param publicKey the given public key
|
||||
* @return the subject key identifier
|
||||
* @throws IOException
|
||||
* @throws NoSuchAlgorithmException
|
||||
*/
|
||||
private SubjectKeyIdentifier getSubjectKeyIdentifier(PublicKey publicKey)
|
||||
throws IOException, NoSuchAlgorithmException {
|
||||
|
||||
InputStream input;
|
||||
SubjectPublicKeyInfo keyInfo;
|
||||
|
||||
input = new ByteArrayInputStream(publicKey.getEncoded());
|
||||
try (final ASN1InputStream is = new ASN1InputStream(input)) {
|
||||
keyInfo = SubjectPublicKeyInfo.getInstance((ASN1Sequence) is.readObject());
|
||||
}
|
||||
|
||||
final JcaX509ExtensionUtils jcaX509ExtensionUtils = new JcaX509ExtensionUtils();
|
||||
return jcaX509ExtensionUtils.createSubjectKeyIdentifier(keyInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random serial number
|
||||
*
|
||||
* @return the serial number
|
||||
*/
|
||||
private long generateSerial() {
|
||||
Date now;
|
||||
|
||||
now = new Date();
|
||||
String sNow = sdfSerial.format(now);
|
||||
|
||||
return Long.valueOf(sNow).longValue();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private static SimpleDateFormat sdfSerial;
|
||||
|
||||
static {
|
||||
sdfSerial = new SimpleDateFormat("yyyyMMddHHmmssSSS");
|
||||
TimeZone tz = TimeZone.getTimeZone("UTC");
|
||||
sdfSerial.setTimeZone(tz);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.io.PrintStream;
|
||||
|
||||
public interface EbicsElement {
|
||||
|
||||
/**
|
||||
* Returns the name of this <code>EbicsElement</code>
|
||||
*
|
||||
* @return the name of the element
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Builds the <code>EbicsElement</code> XML fragment
|
||||
*
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public void build() throws AxelorException;
|
||||
|
||||
/**
|
||||
* Prints the <code>EbicsElement</code> into the given stream.
|
||||
*
|
||||
* @param stream the print stream
|
||||
*/
|
||||
public void print(PrintStream stream);
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Optional information about the client product.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class EbicsProduct implements Serializable {
|
||||
|
||||
/**
|
||||
* Creates a new product information element.
|
||||
*
|
||||
* @param name this is the name of the product. It is a mandatory field.
|
||||
* @param language this is the language. If you use null, the language of the default locale is
|
||||
* used.
|
||||
* @param instituteID the institute, this is an optional value, you can leave this parameter
|
||||
* empty.
|
||||
*/
|
||||
public EbicsProduct(String name, String language, String instituteID) {
|
||||
this.name = name;
|
||||
if (language == null) {
|
||||
language = Locale.getDefault().getLanguage();
|
||||
} else {
|
||||
this.language = language;
|
||||
}
|
||||
this.instituteID = instituteID;
|
||||
}
|
||||
|
||||
/** @return the name */
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/** @param name the name to set */
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/** @return the language */
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
/** @param language the language to set */
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
|
||||
/** @return the instituteID */
|
||||
public String getInstituteID() {
|
||||
return instituteID;
|
||||
}
|
||||
|
||||
/** @param instituteID the instituteID to set */
|
||||
public void setInstituteID(String instituteID) {
|
||||
this.instituteID = instituteID;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private transient String name;
|
||||
private String language;
|
||||
private String instituteID;
|
||||
|
||||
private static final long serialVersionUID = 6400195827756653241L;
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.io.OutputStream;
|
||||
import org.jdom.JDOMException;
|
||||
|
||||
/**
|
||||
* An Ebics root element knows its name.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public interface EbicsRootElement extends EbicsElement {
|
||||
|
||||
/**
|
||||
* Converts the <code>EbicsElement</code> to a byte array
|
||||
*
|
||||
* @return the equivalent byte array of this <code>EbicsElement</code>
|
||||
*/
|
||||
public byte[] toByteArray();
|
||||
|
||||
/**
|
||||
* Validates the request element according to the EBICS XML schema specification
|
||||
*
|
||||
* @throws EbicsException throws an EbicsException when validation fails
|
||||
*/
|
||||
public void validate() throws AxelorException;
|
||||
|
||||
/**
|
||||
* Adds a namespace declaration for the <code>EbicsRootElement</code>
|
||||
*
|
||||
* @param prefix namespace prefix
|
||||
* @param uri namespace uri
|
||||
*/
|
||||
public void addNamespaceDecl(String prefix, String uri);
|
||||
|
||||
/**
|
||||
* Saves the <code>EbicsElement</code> into a given output stream.
|
||||
*
|
||||
* @param out the output stream
|
||||
* @throws EbicsException the save operation fails
|
||||
*/
|
||||
public void save(OutputStream out) throws AxelorException, JDOMException;
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsCertificateRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsCertificateService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.io.IOException;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class EbicsSession {
|
||||
|
||||
private EbicsUser user;
|
||||
private EbicsUser signatoryUser;
|
||||
private EbicsProduct product;
|
||||
private Map<String, String> parameters;
|
||||
|
||||
/**
|
||||
* Constructs a new ebics session
|
||||
*
|
||||
* @param user the ebics user
|
||||
* @param the ebics client configuration
|
||||
*/
|
||||
public EbicsSession(EbicsUser user) {
|
||||
this.user = user;
|
||||
parameters = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ebics session
|
||||
*
|
||||
* @param user the ebics user
|
||||
* @param the ebics client configuration
|
||||
*/
|
||||
public EbicsSession(EbicsUser user, EbicsUser signatoryUser) {
|
||||
this.user = user;
|
||||
this.signatoryUser = signatoryUser;
|
||||
parameters = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the banks encryption key. The key will be fetched automatically form the bank if
|
||||
* needed.
|
||||
*
|
||||
* @return the banks encryption key.
|
||||
* @throws IOException Communication error during key retrieval.
|
||||
* @throws EbicsException Server error message generated during key retrieval.
|
||||
*/
|
||||
public RSAPublicKey getBankE002Key() throws AxelorException {
|
||||
|
||||
return (RSAPublicKey)
|
||||
EbicsCertificateService.getBankCertificate(
|
||||
user.getEbicsPartner().getEbicsBank(), EbicsCertificateRepository.TYPE_ENCRYPTION)
|
||||
.getPublicKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the banks authentication key. The key will be fetched automatically form the bank if
|
||||
* needed.
|
||||
*
|
||||
* @return the banks authentication key.
|
||||
* @throws IOException Communication error during key retrieval.
|
||||
* @throws EbicsException Server error message generated during key retrieval.
|
||||
*/
|
||||
public RSAPublicKey getBankX002Key() throws AxelorException {
|
||||
return (RSAPublicKey)
|
||||
EbicsCertificateService.getBankCertificate(
|
||||
user.getEbicsPartner().getEbicsBank(),
|
||||
EbicsCertificateRepository.TYPE_AUTHENTICATION)
|
||||
.getPublicKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bank id.
|
||||
*
|
||||
* @return the bank id.
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public String getBankID() throws AxelorException {
|
||||
return user.getEbicsPartner().getEbicsBank().getHostId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the session user.
|
||||
*
|
||||
* @return the session user.
|
||||
*/
|
||||
public EbicsUser getUser() {
|
||||
return user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the session signatory user.
|
||||
*
|
||||
* @return the session signatory user.
|
||||
*/
|
||||
public EbicsUser getSignatoryUser() {
|
||||
return signatoryUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional product identification that will be sent to the bank during each request.
|
||||
*
|
||||
* @param product Product description
|
||||
*/
|
||||
public void setProduct(EbicsProduct product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
/** @return the product */
|
||||
public EbicsProduct getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a session parameter to use it in the transfer process.
|
||||
*
|
||||
* @param key the parameter key
|
||||
* @param value the parameter value
|
||||
*/
|
||||
public void addSessionParam(String key, String value) {
|
||||
parameters.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a session parameter using its key.
|
||||
*
|
||||
* @param key the parameter key
|
||||
* @return the session parameter
|
||||
*/
|
||||
public String getSessionParam(String key) {
|
||||
if (key == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return parameters.get(key);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
import com.axelor.app.AppSettings;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.zip.DataFormatException;
|
||||
import java.util.zip.Deflater;
|
||||
import java.util.zip.Inflater;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import org.apache.xml.security.c14n.Canonicalizer;
|
||||
import org.apache.xml.security.utils.IgnoreAllErrorHandler;
|
||||
import org.apache.xpath.XPathAPI;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.traversal.NodeIterator;
|
||||
|
||||
/**
|
||||
* Some utilities for EBICS request creation and reception
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class EbicsUtils {
|
||||
|
||||
/**
|
||||
* Compresses an input of byte array
|
||||
*
|
||||
* <p>The Decompression is ensured via Universal compression algorithm (RFC 1950, RFC 1951) As
|
||||
* specified in the EBICS specification (16 Appendix: Standards and references)
|
||||
*
|
||||
* @param toZip the input to be compressed
|
||||
* @return the compressed input data
|
||||
* @throws IOException compression failed
|
||||
*/
|
||||
public static byte[] zip(byte[] toZip) throws AxelorException {
|
||||
|
||||
if (toZip == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get("The input to be zipped cannot be null"));
|
||||
}
|
||||
|
||||
Deflater compressor;
|
||||
ByteArrayOutputStream output;
|
||||
byte[] buffer;
|
||||
|
||||
output = new ByteArrayOutputStream(toZip.length);
|
||||
buffer = new byte[1024];
|
||||
compressor = new Deflater(Deflater.BEST_COMPRESSION);
|
||||
compressor.setInput(toZip);
|
||||
compressor.finish();
|
||||
|
||||
while (!compressor.finished()) {
|
||||
int count = compressor.deflate(buffer);
|
||||
output.write(buffer, 0, count);
|
||||
}
|
||||
|
||||
try {
|
||||
output.close();
|
||||
} catch (IOException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
compressor.end();
|
||||
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random nonce.
|
||||
*
|
||||
* <p>EBICS Specification 2.4.2 - 11.6 Generation of the transaction IDs:
|
||||
*
|
||||
* <p>Transaction IDs are cryptographically-strong random numbers with a length of 128 bits. This
|
||||
* means that the likelihood of any two bank systems using the same transaction ID at the same
|
||||
* time is sufficiently small.
|
||||
*
|
||||
* <p>Transaction IDs are generated by cryptographic pseudo-random number generators (PRNG) that
|
||||
* have been initialized with a real random number (seed). The entropy of the seed should be at
|
||||
* least 100 bits.
|
||||
*
|
||||
* @return a random nonce.
|
||||
* @throws EbicsException nonce generation fails.
|
||||
*/
|
||||
public static byte[] generateNonce() throws AxelorException {
|
||||
SecureRandom secureRandom;
|
||||
|
||||
try {
|
||||
secureRandom = SecureRandom.getInstance("SHA1PRNG");
|
||||
return secureRandom.generateSeed(16);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AxelorException(e.getCause(), TraceBackRepository.TYPE_FUNCTIONNAL, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uncompresses a given byte array input.
|
||||
*
|
||||
* <p>The Decompression is ensured via Universal compression algorithm (RFC 1950, RFC 1951) As
|
||||
* specified in the EBICS specification (16 Appendix: Standards and references)
|
||||
*
|
||||
* @param zip the zipped input.
|
||||
* @return the uncompressed data.
|
||||
*/
|
||||
public static byte[] unzip(byte[] zip) throws AxelorException {
|
||||
Inflater decompressor;
|
||||
ByteArrayOutputStream output;
|
||||
byte[] buf;
|
||||
|
||||
decompressor = new Inflater();
|
||||
output = new ByteArrayOutputStream(zip.length);
|
||||
decompressor.setInput(zip);
|
||||
buf = new byte[1024];
|
||||
|
||||
while (!decompressor.finished()) {
|
||||
int count;
|
||||
|
||||
try {
|
||||
count = decompressor.inflate(buf);
|
||||
} catch (DataFormatException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.TYPE_FUNCTIONNAL, e.getMessage());
|
||||
}
|
||||
output.write(buf, 0, count);
|
||||
}
|
||||
|
||||
try {
|
||||
output.close();
|
||||
} catch (IOException e) {
|
||||
throw new AxelorException(e.getCause(), TraceBackRepository.TYPE_FUNCTIONNAL, e.getMessage());
|
||||
}
|
||||
|
||||
decompressor.end();
|
||||
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonizes an input with inclusive c14n without comments algorithm.
|
||||
*
|
||||
* <p>EBICS Specification 2.4.2 - 5.5.1.1.1 EBICS messages in transaction initialization:
|
||||
*
|
||||
* <p>The identification and authentication signature includes all XML elements of the EBICS
|
||||
* request whose attribute value for @authenticate is equal to “true”. The definition of the XML
|
||||
* schema “ebics_request.xsd“ guarantees that the value of the attribute @authenticate is equal to
|
||||
* “true” for precisely those elements that also need to be signed.
|
||||
*
|
||||
* <p>Thus, All the Elements with the attribute authenticate = true and their sub elements are
|
||||
* considered for the canonization process. This is performed via the {@link
|
||||
* XPathAPI#selectNodeIterator(Node, String) selectNodeIterator(Node, String)}.
|
||||
*
|
||||
* @param input the byte array XML input.
|
||||
* @return the canonized form of the given XML
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public static byte[] canonize(byte[] input) throws AxelorException {
|
||||
DocumentBuilderFactory factory;
|
||||
DocumentBuilder builder;
|
||||
Document document;
|
||||
NodeIterator iter;
|
||||
ByteArrayOutputStream output;
|
||||
Node node;
|
||||
|
||||
try {
|
||||
factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setValidating(true);
|
||||
builder = factory.newDocumentBuilder();
|
||||
builder.setErrorHandler(new IgnoreAllErrorHandler());
|
||||
document = builder.parse(new ByteArrayInputStream(input));
|
||||
iter = XPathAPI.selectNodeIterator(document, "//*[@authenticate='true']");
|
||||
output = new ByteArrayOutputStream();
|
||||
while ((node = iter.nextNode()) != null) {
|
||||
Canonicalizer canonicalizer;
|
||||
|
||||
canonicalizer = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
|
||||
output.write(canonicalizer.canonicalizeSubtree(node));
|
||||
}
|
||||
|
||||
return output.toByteArray();
|
||||
} catch (Exception e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts an input with a given key spec.
|
||||
*
|
||||
* <p>EBICS Specification 2.4.2 - 15.1 Workflows at the sender’s end:
|
||||
*
|
||||
* <p><b>Preparation for DEK encryption</b>
|
||||
*
|
||||
* <p>The 128 bit DEK that is interpreted as a natural number is filled out with null bits to 768
|
||||
* bits in front of the highest-value bit. The result is called PDEK.
|
||||
*
|
||||
* <p><b>Encryption of the secret DES key</b>
|
||||
*
|
||||
* <p>PDEK is then encrypted with the recipient’s public key of the RSA key system and is then
|
||||
* expanded with leading null bits to 1024 bits.
|
||||
*
|
||||
* <p>The result is called EDEK. It must be ensured that EDEK is not equal to DEK.
|
||||
*
|
||||
* <p><b>Encryption of the messages</b>
|
||||
*
|
||||
* <p><U>Padding of the message:</U>
|
||||
*
|
||||
* <p>The method Padding with Octets in accordance with ANSI X9.23 is used for padding the
|
||||
* message, i.e. in all cases, data is appended to the message that is to be encrypted.
|
||||
*
|
||||
* <p><U>Application of the encryption algorithm:</U>
|
||||
*
|
||||
* <p>The message is encrypted in CBC mode in accordance with ANSI X3.106 with the secret key DEK
|
||||
* according to the 2-key triple DES process as specified in ANSI X3.92-1981.
|
||||
*
|
||||
* <p>In doing this, the following initialization value “ICV” is used: X ‘00 00 00 00 00 00 00
|
||||
* 00’.
|
||||
*
|
||||
* @param input the input to encrypt
|
||||
* @param keySpec the key spec
|
||||
* @return the encrypted input
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public static byte[] encrypt(byte[] input, SecretKeySpec keySpec) throws AxelorException {
|
||||
return encryptOrDecrypt(Cipher.ENCRYPT_MODE, input, keySpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the given input according to key spec.
|
||||
*
|
||||
* @param input the input to decrypt
|
||||
* @param keySpec the key spec
|
||||
* @return the decrypted input
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public static byte[] decrypt(byte[] input, SecretKeySpec keySpec) throws AxelorException {
|
||||
return encryptOrDecrypt(Cipher.DECRYPT_MODE, input, keySpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encrypts or decrypts the given input according to key spec.
|
||||
*
|
||||
* @param mode the encryption-decryption mode.
|
||||
* @param input the input to encrypt or decrypt.
|
||||
* @param keySpec the key spec.
|
||||
* @return the encrypted or decrypted data.
|
||||
* @throws GeneralSecurityException
|
||||
*/
|
||||
private static byte[] encryptOrDecrypt(int mode, byte[] input, SecretKeySpec keySpec)
|
||||
throws AxelorException {
|
||||
IvParameterSpec iv;
|
||||
Cipher cipher;
|
||||
|
||||
iv = new IvParameterSpec(new byte[16]);
|
||||
try {
|
||||
cipher = Cipher.getInstance("AES/CBC/ISO10126Padding", BouncyCastleProvider.PROVIDER_NAME);
|
||||
cipher.init(mode, keySpec, iv);
|
||||
return cipher.doFinal(input);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string date
|
||||
*
|
||||
* @param date the given string date
|
||||
* @return the date value
|
||||
*/
|
||||
public static Date parse(String date) throws AxelorException {
|
||||
try {
|
||||
return new SimpleDateFormat(AppSettings.get().get("date.format")).parse(date);
|
||||
} catch (Exception e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the returned http code
|
||||
*
|
||||
* @param httpCode the http code
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public static void checkHttpCode(int httpCode) throws AxelorException {
|
||||
if (httpCode != 200) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.TYPE_FUNCTIONNAL, "http.code.error[Code:%s]", httpCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsTransferState;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.apps.bankpayment.ebics.io.ByteArrayContentFactory;
|
||||
import com.axelor.apps.bankpayment.ebics.io.Joiner;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.DInitializationRequestElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.DInitializationResponseElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.DTransferRequestElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.DTransferResponseElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.DefaultEbicsRootElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.InitializationResponseElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.ReceiptRequestElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.ReceiptResponseElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.TransferResponseElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.UInitializationRequestElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.UTransferRequestElement;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Date;
|
||||
import org.jdom.JDOMException;
|
||||
|
||||
/**
|
||||
* Handling of file transfers. Files can be transferred to and fetched from the bank. Every transfer
|
||||
* may be performed in a recoverable way. For convenience and performance reasons there are also
|
||||
* methods that do the whole transfer in one method call. To use the recoverable transfer mode, you
|
||||
* may set a working directory for temporarily created files.
|
||||
*
|
||||
* <p>EBICS specification 2.4.2 - 6.2 Encryption at application level
|
||||
*
|
||||
* <p>In the event of an upload transaction, a random symmetrical key is generated in the customer
|
||||
* system that is used exclusively within the framework of this transaction both for encryption of
|
||||
* the ES’s and for encryption of the order data. This key is encrypted asymmetrically with the
|
||||
* financial institution’s public encryption key and is transmitted by the customer system to the
|
||||
* bank system during the initialization phase of the transaction.
|
||||
*
|
||||
* <p>Analogously, in the case of a download transaction a random symmetrical key is generated in
|
||||
* the bank system that is used for encryption of the order data that is to be downloaded and for
|
||||
* encryption of the bank-technical signature that has been provided by the financial institution.
|
||||
* This key is asymmetrically encrypted and is transmitted by the bank system to the customer system
|
||||
* during the initialization phase of the transaction. The asymmetrical encryption takes place with
|
||||
* the technical subscriber’s public encryption key if the transaction’s EBICS messages are sent by
|
||||
* a technical subscriber. Otherwise the asymmetrical encryption takes place with the public
|
||||
* encryption key of the non-technical subscriber, i.e. the submitter of the order.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class FileTransfer {
|
||||
|
||||
/**
|
||||
* Constructs a new FileTransfer session
|
||||
*
|
||||
* @param session the user session
|
||||
*/
|
||||
public FileTransfer(EbicsSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiates a file transfer to the bank.
|
||||
*
|
||||
* @param content The bytes you want to send.
|
||||
* @param orderType As which order type
|
||||
* @throws IOException
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public void sendFile(byte[] content, OrderType orderType, byte[] signature)
|
||||
throws IOException, AxelorException {
|
||||
HttpRequestSender sender;
|
||||
UInitializationRequestElement initializer;
|
||||
InitializationResponseElement response;
|
||||
int httpCode;
|
||||
EbicsTransferState state;
|
||||
|
||||
sender = new HttpRequestSender(session);
|
||||
|
||||
initializer = new UInitializationRequestElement(session, orderType, content, signature);
|
||||
|
||||
initializer.build();
|
||||
|
||||
initializer.validate();
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
try {
|
||||
initializer.save(bout);
|
||||
} catch (JDOMException e) {
|
||||
// TODO Bloc catch généré automatiquement
|
||||
e.printStackTrace();
|
||||
}
|
||||
System.out.println(
|
||||
"Requete ----------------------------------------------------------------------------");
|
||||
System.out.println(bout.toString());
|
||||
|
||||
httpCode = sender.send(new ByteArrayContentFactory(initializer.prettyPrint()));
|
||||
|
||||
EbicsUtils.checkHttpCode(httpCode);
|
||||
response =
|
||||
new InitializationResponseElement(
|
||||
sender.getResponseBody(),
|
||||
orderType,
|
||||
DefaultEbicsRootElement.generateName(orderType),
|
||||
session.getUser());
|
||||
response.build();
|
||||
response.report(new EbicsRootElement[] {initializer, response});
|
||||
state = new EbicsTransferState();
|
||||
state.setNumSegments(initializer.getSegmentNumber());
|
||||
state.setTransactionId(response.getTransactionId());
|
||||
int segNumber = 1;
|
||||
while (segNumber <= state.getNumSegments()) {
|
||||
state.setSegmentNumber(segNumber);
|
||||
if (segNumber == state.getSegmentNumber()) {
|
||||
state.setLastSegment(true);
|
||||
}
|
||||
sendFile(
|
||||
initializer.getContent(segNumber),
|
||||
segNumber,
|
||||
state.getLastSegment(),
|
||||
state.getTransactionId(),
|
||||
orderType);
|
||||
segNumber++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a segment to the ebics bank server.
|
||||
*
|
||||
* @param factory the content factory that contain the segment data.
|
||||
* @param segmentNumber the segment number
|
||||
* @param lastSegment is it the last segment?
|
||||
* @param transactionId the transaction Id
|
||||
* @param orderType the order type
|
||||
* @throws IOException
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public void sendFile(
|
||||
ContentFactory factory,
|
||||
int segmentNumber,
|
||||
boolean lastSegment,
|
||||
byte[] transactionId,
|
||||
OrderType orderType)
|
||||
throws IOException, AxelorException {
|
||||
UTransferRequestElement uploader;
|
||||
HttpRequestSender sender;
|
||||
TransferResponseElement response;
|
||||
int httpCode;
|
||||
|
||||
uploader =
|
||||
new UTransferRequestElement(
|
||||
session, orderType, segmentNumber, lastSegment, transactionId, factory);
|
||||
sender = new HttpRequestSender(session);
|
||||
uploader.build();
|
||||
uploader.validate();
|
||||
httpCode = sender.send(new ByteArrayContentFactory(uploader.prettyPrint()));
|
||||
EbicsUtils.checkHttpCode(httpCode);
|
||||
response =
|
||||
new TransferResponseElement(
|
||||
sender.getResponseBody(),
|
||||
DefaultEbicsRootElement.generateName(orderType),
|
||||
session.getUser());
|
||||
response.build();
|
||||
response.report(new EbicsRootElement[] {uploader, response});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a file of the given order type from the bank. You may give an optional start and end
|
||||
* date. This type of transfer will run until everything is processed. No transaction recovery is
|
||||
* possible.
|
||||
*
|
||||
* @param orderType type of file to fetch
|
||||
* @param start optional begin of fetch term
|
||||
* @param end optional end of fetch term
|
||||
* @param dest where to put the data
|
||||
* @throws IOException communication error
|
||||
* @throws EbicsException server generated error
|
||||
*/
|
||||
public void fetchFile(OrderType orderType, Date start, Date end, OutputStream dest)
|
||||
throws IOException, AxelorException {
|
||||
HttpRequestSender sender;
|
||||
DInitializationRequestElement initializer;
|
||||
DInitializationResponseElement response;
|
||||
ReceiptRequestElement receipt;
|
||||
ReceiptResponseElement receiptResponse;
|
||||
int httpCode;
|
||||
EbicsTransferState state;
|
||||
Joiner joiner;
|
||||
|
||||
sender = new HttpRequestSender(session);
|
||||
initializer = new DInitializationRequestElement(session, orderType, start, end);
|
||||
initializer.build();
|
||||
initializer.validate();
|
||||
httpCode = sender.send(new ByteArrayContentFactory(initializer.prettyPrint()));
|
||||
EbicsUtils.checkHttpCode(httpCode);
|
||||
response =
|
||||
new DInitializationResponseElement(
|
||||
sender.getResponseBody(),
|
||||
orderType,
|
||||
DefaultEbicsRootElement.generateName(orderType),
|
||||
session.getUser());
|
||||
response.build();
|
||||
response.report(new EbicsRootElement[] {initializer, response});
|
||||
state = new EbicsTransferState();
|
||||
state.setSegmentNumber(response.getSegmentsNumber());
|
||||
state.setTransactionId(response.getTransactionId());
|
||||
state.setSegmentNumber(response.getSegmentNumber());
|
||||
joiner = new Joiner(session.getUser());
|
||||
joiner.append(response.getOrderData());
|
||||
while (state.getSegmentNumber() <= state.getNumSegments()) {
|
||||
if (state.getSegmentNumber() == state.getNumSegments()) {
|
||||
state.setLastSegment(true);
|
||||
}
|
||||
fetchFile(
|
||||
orderType,
|
||||
state.getSegmentNumber(),
|
||||
state.getLastSegment(),
|
||||
state.getTransactionId(),
|
||||
joiner);
|
||||
state.setSegmentNumber(state.getSegmentNumber() + 1);
|
||||
}
|
||||
|
||||
joiner.writeTo(dest, response.getTransactionKey());
|
||||
receipt =
|
||||
new ReceiptRequestElement(
|
||||
session, state.getTransactionId(), DefaultEbicsRootElement.generateName(orderType));
|
||||
receipt.build();
|
||||
receipt.validate();
|
||||
httpCode = sender.send(new ByteArrayContentFactory(receipt.prettyPrint()));
|
||||
EbicsUtils.checkHttpCode(httpCode);
|
||||
receiptResponse =
|
||||
new ReceiptResponseElement(
|
||||
sender.getResponseBody(),
|
||||
DefaultEbicsRootElement.generateName(orderType),
|
||||
session.getUser());
|
||||
receiptResponse.build();
|
||||
receiptResponse.report(new EbicsRootElement[] {receipt, receiptResponse});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a given portion of a file.
|
||||
*
|
||||
* @param orderType the order type
|
||||
* @param segmentNumber the segment number
|
||||
* @param lastSegment is it the last segment?
|
||||
* @param transactionId the transaction ID
|
||||
* @param joiner the portions joiner
|
||||
* @throws IOException communication error
|
||||
* @throws EbicsException server generated error
|
||||
*/
|
||||
public void fetchFile(
|
||||
OrderType orderType,
|
||||
int segmentNumber,
|
||||
boolean lastSegment,
|
||||
byte[] transactionId,
|
||||
Joiner joiner)
|
||||
throws IOException, AxelorException {
|
||||
DTransferRequestElement downloader;
|
||||
HttpRequestSender sender;
|
||||
DTransferResponseElement response;
|
||||
int httpCode;
|
||||
|
||||
sender = new HttpRequestSender(session);
|
||||
downloader =
|
||||
new DTransferRequestElement(session, orderType, segmentNumber, lastSegment, transactionId);
|
||||
downloader.build();
|
||||
downloader.validate();
|
||||
httpCode = sender.send(new ByteArrayContentFactory(downloader.prettyPrint()));
|
||||
EbicsUtils.checkHttpCode(httpCode);
|
||||
response =
|
||||
new DTransferResponseElement(
|
||||
sender.getResponseBody(),
|
||||
orderType,
|
||||
DefaultEbicsRootElement.generateName(orderType),
|
||||
session.getUser());
|
||||
response.build();
|
||||
response.report(new EbicsRootElement[] {downloader, response});
|
||||
joiner.append(response.getOrderData());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private EbicsSession session;
|
||||
}
|
||||
@ -0,0 +1,262 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
import com.axelor.app.AppSettings;
|
||||
import com.axelor.apps.bankpayment.db.EbicsBank;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsCertificateRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsCertificateService;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.net.URL;
|
||||
import java.security.KeyStore;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import javax.net.ssl.SSLException;
|
||||
import org.apache.commons.httpclient.HostConfiguration;
|
||||
import org.apache.commons.httpclient.HttpClient;
|
||||
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
|
||||
import org.apache.commons.httpclient.methods.PostMethod;
|
||||
import org.apache.commons.httpclient.methods.RequestEntity;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.auth.AuthScope;
|
||||
import org.apache.http.auth.Credentials;
|
||||
import org.apache.http.auth.UsernamePasswordCredentials;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.conn.scheme.Scheme;
|
||||
import org.apache.http.conn.ssl.SSLSocketFactory;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.InputStreamEntity;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.params.BasicHttpParams;
|
||||
import org.apache.http.params.HttpConnectionParams;
|
||||
import org.apache.http.params.HttpParams;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A simple HTTP request sender and receiver. The send returns a HTTP code that should be analyzed
|
||||
* before proceeding ebics request response parse.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class HttpRequestSender {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
/**
|
||||
* Constructs a new <code>HttpRequestSender</code> with a given ebics session.
|
||||
*
|
||||
* @param session the ebics session
|
||||
*/
|
||||
public HttpRequestSender(EbicsSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the request contained in the <code>ContentFactory</code>. The <code>ContentFactory</code>
|
||||
* will deliver the request as an <code>InputStream</code>.
|
||||
*
|
||||
* @param request the ebics request
|
||||
* @return the HTTP return code
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public final int send(ContentFactory request) throws IOException, AxelorException {
|
||||
|
||||
EbicsBank bank = session.getUser().getEbicsPartner().getEbicsBank();
|
||||
String url = bank.getUrl();
|
||||
if (url == null || !url.startsWith("http://") && !url.startsWith("https://")) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get(IExceptionMessage.EBICS_INVALID_BANK_URL));
|
||||
}
|
||||
|
||||
if (bank.getProtocolSelect().equals("ssl")) {
|
||||
return sendSSL(request, bank);
|
||||
} else {
|
||||
return sendTLS(request, bank);
|
||||
}
|
||||
}
|
||||
|
||||
public final int sendSSL(ContentFactory request, EbicsBank bank)
|
||||
throws AxelorException, IOException {
|
||||
String url = bank.getUrl();
|
||||
X509Certificate certificate =
|
||||
EbicsCertificateService.getBankCertificate(bank, EbicsCertificateRepository.TYPE_SSL);
|
||||
DefaultHttpClient client = getSecuredHttpClient(certificate, url);
|
||||
String proxyConfiguration = AppSettings.get().get("http.proxy.host");
|
||||
|
||||
if (proxyConfiguration != null && !proxyConfiguration.equals("")) {
|
||||
setProxy(client);
|
||||
}
|
||||
|
||||
InputStream input = request.getContent();
|
||||
int retCode = -1;
|
||||
log.debug("Bank url: {}", url);
|
||||
HttpPost post = new HttpPost(url);
|
||||
ContentType type = ContentType.TEXT_XML;
|
||||
HttpEntity entity = new InputStreamEntity(input, retCode, type);
|
||||
post.setEntity(entity);
|
||||
|
||||
try {
|
||||
HttpResponse responseHttp = client.execute(post);
|
||||
retCode = responseHttp.getStatusLine().getStatusCode();
|
||||
log.debug("Http reason phrase: {}", responseHttp.getStatusLine().getReasonPhrase());
|
||||
response = new InputStreamContentFactory(responseHttp.getEntity().getContent());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new AxelorException(
|
||||
e.getCause(),
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get("Connection error: %s"),
|
||||
e.getMessage());
|
||||
}
|
||||
|
||||
return retCode;
|
||||
}
|
||||
|
||||
public final int sendTLS(ContentFactory request, EbicsBank bank) throws IOException {
|
||||
HttpClient httpClient;
|
||||
PostMethod method;
|
||||
RequestEntity requestEntity;
|
||||
InputStream input;
|
||||
int retCode;
|
||||
httpClient = new HttpClient();
|
||||
String proxyConfiguration = AppSettings.get().get("http.proxy.host");
|
||||
|
||||
if (proxyConfiguration != null && !proxyConfiguration.equals("")) {
|
||||
setProxy(httpClient);
|
||||
}
|
||||
input = request.getContent();
|
||||
method = new PostMethod(bank.getUrl());
|
||||
method.getParams().setSoTimeout(30000);
|
||||
requestEntity = new InputStreamRequestEntity(input);
|
||||
method.setRequestEntity(requestEntity);
|
||||
method.setRequestHeader("Content-type", "text/xml; charset=ISO-8859-1");
|
||||
retCode = -1;
|
||||
retCode = httpClient.executeMethod(method);
|
||||
response = new InputStreamContentFactory(method.getResponseBodyAsStream());
|
||||
|
||||
return retCode;
|
||||
}
|
||||
|
||||
private void setProxy(DefaultHttpClient client) {
|
||||
|
||||
String proxyHost;
|
||||
int proxyPort;
|
||||
|
||||
proxyHost = AppSettings.get().get("http.proxy.host").trim();
|
||||
proxyPort = Integer.parseInt(AppSettings.get().get("http.proxy.port").trim());
|
||||
if (!AppSettings.get().get("http.proxy.user").equals("")) {
|
||||
String user;
|
||||
String pwd;
|
||||
Credentials credentials;
|
||||
AuthScope authscope;
|
||||
|
||||
user = AppSettings.get().get("http.proxy.user").trim();
|
||||
pwd = AppSettings.get().get("http.proxy.password").trim();
|
||||
credentials = new UsernamePasswordCredentials(user, pwd);
|
||||
authscope = new AuthScope(proxyHost, proxyPort);
|
||||
client.getCredentialsProvider().setCredentials(authscope, credentials);
|
||||
}
|
||||
}
|
||||
|
||||
private void setProxy(HttpClient httpClient) {
|
||||
|
||||
String proxyHost = AppSettings.get().get("http.proxy.host").trim();
|
||||
Integer proxyPort = Integer.parseInt(AppSettings.get().get("http.proxy.port").trim());
|
||||
HostConfiguration hostConfig = httpClient.getHostConfiguration();
|
||||
hostConfig.setProxy(proxyHost, proxyPort);
|
||||
if (!AppSettings.get().get("http.proxy.user").equals("")) {
|
||||
String user;
|
||||
String pwd;
|
||||
org.apache.commons.httpclient.UsernamePasswordCredentials credentials;
|
||||
org.apache.commons.httpclient.auth.AuthScope authscope;
|
||||
|
||||
user = AppSettings.get().get("http.proxy.user").trim();
|
||||
pwd = AppSettings.get().get("http.proxy.password").trim();
|
||||
credentials = new org.apache.commons.httpclient.UsernamePasswordCredentials(user, pwd);
|
||||
authscope = new org.apache.commons.httpclient.auth.AuthScope(proxyHost, proxyPort);
|
||||
httpClient.getState().setProxyCredentials(authscope, credentials);
|
||||
}
|
||||
}
|
||||
|
||||
private DefaultHttpClient getSecuredHttpClient(Certificate cert, String bankURL)
|
||||
throws AxelorException {
|
||||
|
||||
HttpParams httpParams = new BasicHttpParams();
|
||||
HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
|
||||
HttpConnectionParams.setSoTimeout(httpParams, 30000);
|
||||
DefaultHttpClient client = new DefaultHttpClient(httpParams);
|
||||
|
||||
try {
|
||||
Scheme https = null;
|
||||
if (cert != null) {
|
||||
log.debug("SSL certificate exist");
|
||||
URL url = new URL(bankURL);
|
||||
log.debug("Url host: {}", url.getHost());
|
||||
KeyStore keystore = KeyStore.getInstance("jks");
|
||||
char[] password = "NoPassword".toCharArray();
|
||||
keystore.load(null, password);
|
||||
keystore.setCertificateEntry(url.getHost(), cert);
|
||||
SSLSocketFactory factory = new SSLSocketFactory(keystore);
|
||||
try {
|
||||
factory.getHostnameVerifier().verify(url.getHost(), (X509Certificate) cert);
|
||||
https = new Scheme("https", 443, new SSLSocketFactory(keystore));
|
||||
} catch (SSLException e) {
|
||||
log.debug("Error in ssl certifcate host name verification");
|
||||
https = new Scheme("https", 443, SSLSocketFactory.getSocketFactory());
|
||||
}
|
||||
|
||||
} else {
|
||||
log.debug("SSL certificate not exist");
|
||||
https = new Scheme("https", 443, SSLSocketFactory.getSocketFactory());
|
||||
}
|
||||
client.getConnectionManager().getSchemeRegistry().register(https);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.TYPE_TECHNICAL, I18n.get("Error adding certificate"));
|
||||
}
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content factory of the response body
|
||||
*
|
||||
* @return the content factory of the response.
|
||||
*/
|
||||
public ContentFactory getResponseBody() {
|
||||
return response;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// DATA MEMBERS
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
private EbicsSession session;
|
||||
private ContentFactory response;
|
||||
}
|
||||
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990-2012 kopiLeft Development SARL, Bizerte, Tunisia
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Input stream content factory that delivers the its content as an <code>InputStream</code> This
|
||||
* object is serializable in a way to recover interrupted file transfers.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class InputStreamContentFactory implements ContentFactory {
|
||||
|
||||
/**
|
||||
* Creates a new <code>ContentFactory</code> from an input stream
|
||||
*
|
||||
* @param input the given input stream.
|
||||
*/
|
||||
public InputStreamContentFactory(InputStream input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getContent() throws IOException {
|
||||
return input;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private InputStream input;
|
||||
}
|
||||
@ -0,0 +1,228 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
import com.axelor.apps.bankpayment.ebics.certificate.KeyStoreManager;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.apps.bankpayment.ebics.io.ByteArrayContentFactory;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsUserService;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.HIARequestElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.HPBRequestElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.HPBResponseOrderDataElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.INIRequestElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.KeyManagementResponseElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.SPRRequestElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.SPRResponseElement;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import org.jdom.JDOMException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Everything that has to do with key handling. If you have a totally new account use <code>
|
||||
* sendINI()</code> and <code>sendHIA()</code> to send you newly created keys to the bank. Then wait
|
||||
* until the bank activated your keys. If you are migrating from FTAM. Just send HPB, your EBICS
|
||||
* account should be usable without delay.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class KeyManagement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>KeyManagement</code> instance with a given ebics session
|
||||
*
|
||||
* @param session the ebics session
|
||||
*/
|
||||
public KeyManagement(EbicsSession session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
/**
|
||||
* Sends the user's signature key (A005) to the bank. After successful operation the user is in
|
||||
* state "initialized".
|
||||
*
|
||||
* @param orderId the order ID. Let it null to generate a random one.
|
||||
* @throws EbicsException server generated error message
|
||||
* @throws IOException communication error
|
||||
* @throws AxelorException
|
||||
* @throws JDOMException
|
||||
*/
|
||||
public void sendINI() throws IOException, AxelorException, JDOMException {
|
||||
INIRequestElement request;
|
||||
KeyManagementResponseElement response;
|
||||
HttpRequestSender sender;
|
||||
int httpCode;
|
||||
sender = new HttpRequestSender(session);
|
||||
log.debug("HttpRequestSender OK");
|
||||
request = new INIRequestElement(session);
|
||||
log.debug("INIRequestElement OK");
|
||||
request.build();
|
||||
log.debug("build OK");
|
||||
request.validate();
|
||||
log.debug("validate OK");
|
||||
// session.getConfiguration().getTraceManager().trace(request);
|
||||
httpCode = sender.send(new ByteArrayContentFactory(request.prettyPrint()));
|
||||
log.debug("send OK");
|
||||
EbicsUtils.checkHttpCode(httpCode);
|
||||
log.debug("checkHttpCode OK");
|
||||
response =
|
||||
new KeyManagementResponseElement(
|
||||
sender.getResponseBody(), "INIResponse", session.getUser());
|
||||
log.debug("KeyManagementResponseElement OK");
|
||||
response.build();
|
||||
log.debug("build OK");
|
||||
// session.getConfiguration().getTraceManager().trace(response);
|
||||
response.report(new EbicsRootElement[] {request, response});
|
||||
log.debug("report OK");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the public part of the protocol keys to the bank.
|
||||
*
|
||||
* @param orderId the order ID. Let it null to generate a random one.
|
||||
* @throws IOException communication error
|
||||
* @throws JDOMException
|
||||
* @throws EbicsException server generated error message
|
||||
*/
|
||||
public void sendHIA() throws IOException, AxelorException, JDOMException {
|
||||
HIARequestElement request;
|
||||
KeyManagementResponseElement response;
|
||||
HttpRequestSender sender;
|
||||
int httpCode;
|
||||
|
||||
sender = new HttpRequestSender(session);
|
||||
request = new HIARequestElement(session);
|
||||
request.build();
|
||||
request.validate();
|
||||
// session.getConfiguration().getTraceManager().trace(request);
|
||||
httpCode = sender.send(new ByteArrayContentFactory(request.prettyPrint()));
|
||||
EbicsUtils.checkHttpCode(httpCode);
|
||||
response =
|
||||
new KeyManagementResponseElement(
|
||||
sender.getResponseBody(), "HIAResponse", session.getUser());
|
||||
response.build();
|
||||
// session.getConfiguration().getTraceManager().trace(response);
|
||||
response.report(new EbicsRootElement[] {request, response});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends encryption and authentication keys to the bank. This order is only allowed for a new user
|
||||
* at the bank side that has been created by copying the A005 key. The keys will be activated
|
||||
* immediately after successful completion of the transfer.
|
||||
*
|
||||
* @param orderId the order ID. Let it null to generate a random one.
|
||||
* @throws IOException communication error
|
||||
* @throws GeneralSecurityException data decryption error
|
||||
* @throws AxelorException
|
||||
* @throws JDOMException
|
||||
* @throws EbicsException server generated error message
|
||||
*/
|
||||
public X509Certificate[] sendHPB()
|
||||
throws IOException, GeneralSecurityException, AxelorException, JDOMException {
|
||||
|
||||
HPBRequestElement request;
|
||||
KeyManagementResponseElement response;
|
||||
HttpRequestSender sender;
|
||||
HPBResponseOrderDataElement orderData;
|
||||
ContentFactory factory;
|
||||
int httpCode;
|
||||
|
||||
sender = new HttpRequestSender(session);
|
||||
request = new HPBRequestElement(session);
|
||||
request.build();
|
||||
request.validate();
|
||||
httpCode = sender.send(new ByteArrayContentFactory(request.prettyPrint()));
|
||||
EbicsUtils.checkHttpCode(httpCode);
|
||||
response =
|
||||
new KeyManagementResponseElement(
|
||||
sender.getResponseBody(), "HBPResponse", session.getUser());
|
||||
response.build();
|
||||
response.report(new EbicsRootElement[] {request, response});
|
||||
EbicsUserService userService = Beans.get(EbicsUserService.class);
|
||||
factory =
|
||||
new ByteArrayContentFactory(
|
||||
EbicsUtils.unzip(
|
||||
userService.decrypt(
|
||||
session.getUser(), response.getOrderData(), response.getTransactionKey())));
|
||||
orderData = new HPBResponseOrderDataElement(factory, session.getUser());
|
||||
orderData.build();
|
||||
|
||||
return createCertificates(orderData);
|
||||
}
|
||||
|
||||
private X509Certificate[] createCertificates(HPBResponseOrderDataElement orderData)
|
||||
throws AxelorException, GeneralSecurityException, IOException {
|
||||
|
||||
KeyStoreManager keystoreManager = new KeyStoreManager();
|
||||
if (session.getUser().getPassword() != null) {
|
||||
keystoreManager.load("", session.getUser().getPassword().toCharArray());
|
||||
} else {
|
||||
keystoreManager.load("", null);
|
||||
}
|
||||
|
||||
String certId = session.getBankID() + "-E002";
|
||||
keystoreManager.setCertificateEntry(
|
||||
certId, new ByteArrayInputStream(orderData.getBankE002Certificate()));
|
||||
X509Certificate certificateE002 = keystoreManager.getCertificate(certId);
|
||||
|
||||
certId = session.getBankID() + "-X002";
|
||||
keystoreManager.setCertificateEntry(
|
||||
certId, new ByteArrayInputStream(orderData.getBankX002Certificate()));
|
||||
X509Certificate certificateX002 = keystoreManager.getCertificate(certId);
|
||||
|
||||
return new X509Certificate[] {certificateE002, certificateX002};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the SPR order to the bank. After that you have to start over with sending INI and HIA.
|
||||
*
|
||||
* @throws IOException Communication exception
|
||||
* @throws AxelorException
|
||||
* @throws JDOMException
|
||||
* @throws EbicsException Error message generated by the bank.
|
||||
*/
|
||||
public void lockAccess() throws IOException, AxelorException, JDOMException {
|
||||
HttpRequestSender sender;
|
||||
SPRRequestElement request;
|
||||
SPRResponseElement response;
|
||||
int httpCode;
|
||||
|
||||
sender = new HttpRequestSender(session);
|
||||
request = new SPRRequestElement(session);
|
||||
request.build();
|
||||
request.validate();
|
||||
httpCode = sender.send(new ByteArrayContentFactory(request.prettyPrint()));
|
||||
EbicsUtils.checkHttpCode(httpCode);
|
||||
response = new SPRResponseElement(sender.getResponseBody(), session.getUser());
|
||||
response.build();
|
||||
response.report(new EbicsRootElement[] {request, response});
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private EbicsSession session;
|
||||
}
|
||||
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsPartnerRepository;
|
||||
|
||||
/**
|
||||
* 12.3 Order attributes The following settings are permissible for the order attribute (5 bytes
|
||||
* alphanumeric) in EBICS
|
||||
*/
|
||||
public class OrderAttribute {
|
||||
|
||||
/**
|
||||
* Type of transmitted data O = order data and ES’s U = bank-technical ES’s D = order data and
|
||||
* transport ES (D is also used for HIA, INI, HPB)
|
||||
*/
|
||||
private char transmittedDataType;
|
||||
/** O = order data and ES’s */
|
||||
public static final char TRANSMITTED_DATA_TYPE_O = 'O';
|
||||
/** U = bank-technical ES’s */
|
||||
public static final char TRANSMITTED_DATA_TYPE_U = 'U';
|
||||
/** D = order data and transport ES (D is also used for HIA, INI, HPB) */
|
||||
public static final char TRANSMITTED_DATA_TYPE_D = 'D';
|
||||
|
||||
/** Compression type for order data and/or ES’s Z = ZIP compression */
|
||||
private char compressionType;
|
||||
|
||||
/** Z = ZIP compression */
|
||||
public static final char COMPRESSION_TYPE_Z = 'Z';
|
||||
|
||||
/** Encryption type for order data and/or ES’s N = no encryption H = hybrid process AES/RSA */
|
||||
private char encryptionType;
|
||||
/** N = no encryption */
|
||||
public static final char ENCRYPTION_TYPE_N = 'N';
|
||||
/** H = hybrid process AES/RSA */
|
||||
public static final char ENCRYPTION_TYPE_H = 'H';
|
||||
|
||||
public static final char RESERVED_POSITION = 'N';
|
||||
|
||||
private String orderAttributes;
|
||||
|
||||
public char computeTransmittedDataType(OrderType orderType, int ebicsTypeSelect) {
|
||||
if (orderType.equals(OrderType.INI)) {
|
||||
return TRANSMITTED_DATA_TYPE_D;
|
||||
} else if (orderType.equals(OrderType.HIA)) {
|
||||
return TRANSMITTED_DATA_TYPE_D;
|
||||
} else if (orderType.equals(OrderType.HPB)) {
|
||||
return TRANSMITTED_DATA_TYPE_D;
|
||||
} else if (orderType.equals(OrderType.FUL)) {
|
||||
if (ebicsTypeSelect == EbicsPartnerRepository.EBICS_TYPE_T) {
|
||||
return TRANSMITTED_DATA_TYPE_D;
|
||||
} else if (ebicsTypeSelect == EbicsPartnerRepository.EBICS_TYPE_TS) {
|
||||
return TRANSMITTED_DATA_TYPE_O;
|
||||
}
|
||||
} else if (orderType.equals(OrderType.FDL)
|
||||
|| orderType.equals(OrderType.HTD)
|
||||
|| orderType.equals(OrderType.HPD)
|
||||
|| orderType.equals(OrderType.PTK)) {
|
||||
return TRANSMITTED_DATA_TYPE_D;
|
||||
// "O" if the bank use financial institution’s bank-technical ES
|
||||
} else if (orderType.equals(OrderType.SPR)) {
|
||||
return TRANSMITTED_DATA_TYPE_U;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("NOT SUPPORTED ORDER TYPE OR EBICS MODE");
|
||||
}
|
||||
|
||||
public char computeCompressionType() {
|
||||
return COMPRESSION_TYPE_Z;
|
||||
}
|
||||
|
||||
public char computeEncryptionType(OrderType orderType) {
|
||||
if (orderType.equals(OrderType.INI)) {
|
||||
return ENCRYPTION_TYPE_N;
|
||||
} else if (orderType.equals(OrderType.HIA)) {
|
||||
return ENCRYPTION_TYPE_N;
|
||||
} else if (orderType.equals(OrderType.HPB)) {
|
||||
return ENCRYPTION_TYPE_H;
|
||||
} else if (orderType.equals(OrderType.FUL)) {
|
||||
return ENCRYPTION_TYPE_H;
|
||||
} else if (orderType.equals(OrderType.FDL)
|
||||
|| orderType.equals(OrderType.HTD)
|
||||
|| orderType.equals(OrderType.HPD)
|
||||
|| orderType.equals(OrderType.PTK)) {
|
||||
return ENCRYPTION_TYPE_H;
|
||||
} else if (orderType.equals(OrderType.SPR)) {
|
||||
return ENCRYPTION_TYPE_H;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("NOT SUPPORTED ORDER TYPE OR EBICS MODE");
|
||||
}
|
||||
|
||||
/**
|
||||
* Depending on order type and possible further marginal conditions, an EBICS client MUST enter
|
||||
* the following order attributes in the control data of the first EBICS request of an EBICS
|
||||
* transaction (ebicsRequest/header/static/OrderDetails/OrderAttribute):
|
||||
*
|
||||
* <p>Order type | Marginal conditions | Order attributes
|
||||
* --------------------------------------------------------------------------------------------
|
||||
* INI | - | DZNNN HIA | - | DZNNN HSA | - | OZNNN HPB | - | DZHNN PUB | - | OZHNN HCA | - |
|
||||
* OZHNN HCS | - | OZHNN SPR | - | UZHNN HVE | - | UZHNN HVS | - | UZHNN other upload order types
|
||||
* | order data and ES(s) | OZHNN other upload order types | only bank-technical ES(s), no order
|
||||
* data | UZHNN other upload order types | order data with transport signature | DZHNN | (release
|
||||
* of the order via accompanying | | note instead of bank-technical ES) | other download order
|
||||
* types | download data request with financial | OZHNN | institution’s banktechnical ES | other
|
||||
* download order types | download data request without financial | DZHNN | institution’s
|
||||
* banktechnical ES |
|
||||
*
|
||||
* @param orderType
|
||||
* @param ebicsTypeSelect
|
||||
*/
|
||||
public OrderAttribute(OrderType orderType, int ebicsTypeSelect) {
|
||||
|
||||
this.transmittedDataType = computeTransmittedDataType(orderType, ebicsTypeSelect);
|
||||
this.compressionType = computeCompressionType();
|
||||
this.encryptionType = computeEncryptionType(orderType);
|
||||
}
|
||||
|
||||
public OrderAttribute(char transmittedDataType, char compressionType, char encryptionType) {
|
||||
this.transmittedDataType = transmittedDataType;
|
||||
this.compressionType = compressionType;
|
||||
this.encryptionType = encryptionType;
|
||||
}
|
||||
|
||||
public OrderAttribute build() {
|
||||
|
||||
orderAttributes =
|
||||
new StringBuilder()
|
||||
.append(transmittedDataType)
|
||||
.append(compressionType)
|
||||
.append(encryptionType)
|
||||
.append(RESERVED_POSITION)
|
||||
.append(RESERVED_POSITION)
|
||||
.toString();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/** @return the orderType */
|
||||
public String getOrderAttributes() {
|
||||
return orderAttributes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof OrderAttribute) {
|
||||
return orderAttributes.equals(((OrderAttribute) obj).getOrderAttributes());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
/**
|
||||
* A BCS order type.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class OrderType {
|
||||
|
||||
/**
|
||||
* Constructs new Order type instance
|
||||
*
|
||||
* @param orderType the order type
|
||||
*/
|
||||
public OrderType(String orderType) {
|
||||
this.orderType = orderType;
|
||||
}
|
||||
|
||||
/** @return the orderType */
|
||||
public String getOrderType() {
|
||||
return orderType;
|
||||
}
|
||||
|
||||
/** @param orderType the orderType to set */
|
||||
public void setOrderType(String orderType) {
|
||||
this.orderType = orderType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the corresponding <code>OrderType</code> to a given string order type.
|
||||
*
|
||||
* @param orderType the given order type.
|
||||
* @return the corresponding <code>OrderType</code>
|
||||
*/
|
||||
public static OrderType toOrderType(String orderType) {
|
||||
if (orderType.equals("INI")) {
|
||||
return INI;
|
||||
} else if (orderType.equals("HIA")) {
|
||||
return HIA;
|
||||
} else if (orderType.equals("HPB")) {
|
||||
return HPB;
|
||||
} else if (orderType.equals("FUL")) {
|
||||
return FUL;
|
||||
} else if (orderType.equals("FDL")) {
|
||||
return FDL;
|
||||
} else if (orderType.equals("HTD")) {
|
||||
return HTD;
|
||||
} else if (orderType.equals("HPD")) {
|
||||
return HPD;
|
||||
} else if (orderType.equals("PTK")) {
|
||||
return PTK;
|
||||
} else if (orderType.equals("SPR")) {
|
||||
return SPR;
|
||||
} else {
|
||||
throw new IllegalArgumentException("NOT SUPPORTED ORDER TYPE");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof OrderType) {
|
||||
return orderType.equals(((OrderType) obj).getOrderType());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private String orderType;
|
||||
|
||||
/** Send the users protocol keys. */
|
||||
public static final OrderType HIA;
|
||||
|
||||
/** Fetch the banks protocol keys. */
|
||||
public static final OrderType HPB;
|
||||
|
||||
/** Return bank parameters. */
|
||||
public static final OrderType HPD;
|
||||
|
||||
/** Fetch user informations. */
|
||||
public static final OrderType HTD;
|
||||
|
||||
/** Send the first signature key. */
|
||||
public static final OrderType INI;
|
||||
|
||||
/** File upload */
|
||||
public static final OrderType FUL;
|
||||
|
||||
/** File download */
|
||||
public static final OrderType FDL;
|
||||
|
||||
/** Lock the channel. */
|
||||
public static final OrderType SPR;
|
||||
|
||||
public static final OrderType PTK;
|
||||
|
||||
static {
|
||||
HIA = new OrderType("HIA");
|
||||
HPB = new OrderType("HPB");
|
||||
HPD = new OrderType("HPD");
|
||||
HTD = new OrderType("HTD");
|
||||
INI = new OrderType("INI");
|
||||
FUL = new OrderType("FUL");
|
||||
FDL = new OrderType("FDL");
|
||||
SPR = new OrderType("SPR");
|
||||
PTK = new OrderType("PTK");
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.client;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsUnsecuredRequestDocument.EbicsUnsecuredRequest;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsUnsecuredRequestDocument.EbicsUnsecuredRequest.Body;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsUnsecuredRequestDocument.EbicsUnsecuredRequest.Body.DataTransfer;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsUnsecuredRequestDocument.EbicsUnsecuredRequest.Body.DataTransfer.OrderData;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsUnsecuredRequestDocument.EbicsUnsecuredRequest.Header;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EmptyMutableHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.OrderDetailsType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.ProductElementType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.UnsecuredRequestStaticHeaderType;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.DefaultEbicsRootElement;
|
||||
import com.axelor.apps.bankpayment.ebics.xml.EbicsXmlFactory;
|
||||
import com.axelor.auth.AuthUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>UnsecuredRequestElement</code> is the common element used for key management requests.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class UnsecuredRequestElement extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Constructs a Unsecured Request Element.
|
||||
*
|
||||
* @param session the ebics session.
|
||||
* @param orderType the order type (INI | HIA).
|
||||
* @param orderId the order id, if null a random one is generated.
|
||||
*/
|
||||
public UnsecuredRequestElement(EbicsSession session, OrderType orderType, byte[] orderData) {
|
||||
super(session);
|
||||
this.orderType = orderType;
|
||||
this.orderData = orderData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
Header header;
|
||||
Body body;
|
||||
EmptyMutableHeaderType mutable;
|
||||
UnsecuredRequestStaticHeaderType xstatic;
|
||||
ProductElementType productType;
|
||||
OrderDetailsType orderDetails;
|
||||
DataTransfer dataTransfer;
|
||||
OrderData orderData;
|
||||
EbicsUnsecuredRequest request;
|
||||
|
||||
orderDetails =
|
||||
EbicsXmlFactory.createOrderDetailsType(
|
||||
"DZNNN", session.getUser().getNextOrderId(), orderType.getOrderType());
|
||||
|
||||
productType =
|
||||
EbicsXmlFactory.creatProductElementType(
|
||||
AuthUtils.getUser().getLanguage(), session.getProduct().getName());
|
||||
|
||||
try {
|
||||
xstatic =
|
||||
EbicsXmlFactory.createUnsecuredRequestStaticHeaderType(
|
||||
session.getBankID(),
|
||||
session.getUser().getEbicsPartner().getPartnerId(),
|
||||
session.getUser().getUserId(),
|
||||
productType,
|
||||
orderDetails,
|
||||
session.getUser().getSecurityMedium());
|
||||
mutable = EbicsXmlFactory.createEmptyMutableHeaderType();
|
||||
|
||||
header = EbicsXmlFactory.createHeader(true, mutable, xstatic);
|
||||
|
||||
orderData = EbicsXmlFactory.createOrderData(this.orderData);
|
||||
dataTransfer = EbicsXmlFactory.createDataTransfer(orderData);
|
||||
body = EbicsXmlFactory.createBody(dataTransfer);
|
||||
request = EbicsXmlFactory.createEbicsUnsecuredRequest(header, body, 1, "H003");
|
||||
|
||||
document = EbicsXmlFactory.createEbicsUnsecuredRequestDocument(request);
|
||||
|
||||
} catch (AxelorException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "UnsecuredRequest.xml";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private OrderType orderType;
|
||||
private byte[] orderData;
|
||||
}
|
||||
@ -0,0 +1,287 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.exception;
|
||||
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
|
||||
/**
|
||||
* Representation of EBICS return codes. The return codes are described in chapter 13 of EBICS
|
||||
* specification.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class ReturnCode {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ReturnCode</code> with a given standard code, symbolic name and text
|
||||
*
|
||||
* @param code the given standard code.
|
||||
* @param symbolicName the symbolic name.
|
||||
* @param the code text
|
||||
*/
|
||||
public ReturnCode(String code, String symbolicName, String text) {
|
||||
this.code = code;
|
||||
this.symbolicName = symbolicName;
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an equivalent <code>EbicsException</code>
|
||||
*
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public void throwException() throws AxelorException {
|
||||
throw new AxelorException(TraceBackRepository.TYPE_FUNCTIONNAL, I18n.get(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells if the return code is an OK one.
|
||||
*
|
||||
* @return True if the return code is OK one.
|
||||
*/
|
||||
public boolean isOk() {
|
||||
return equals(EBICS_OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a slightly more human readable version of this return code.
|
||||
*
|
||||
* @return a slightly more human readable version of this return code.
|
||||
*/
|
||||
public String getSymbolicName() {
|
||||
return symbolicName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a display text for the default locale.
|
||||
*
|
||||
* @return a text that can be displayed.
|
||||
*/
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code.
|
||||
*
|
||||
* @return the code.
|
||||
*/
|
||||
public int getCode() {
|
||||
return Integer.parseInt(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the equivalent <code>ReturnCode</code> of a given code
|
||||
*
|
||||
* @param code the given code
|
||||
* @param text the given code text
|
||||
* @return the equivalent <code>ReturnCode</code>
|
||||
*/
|
||||
public static ReturnCode toReturnCode(String code, String text) {
|
||||
if (code.equals(EBICS_OK.code)) {
|
||||
return EBICS_OK;
|
||||
} else if (code.equals(EBICS_DOWNLOAD_POSTPROCESS_DONE.code)) {
|
||||
return EBICS_DOWNLOAD_POSTPROCESS_DONE;
|
||||
} else if (code.equals(EBICS_DOWNLOAD_POSTPROCESS_SKIPPED.code)) {
|
||||
return EBICS_DOWNLOAD_POSTPROCESS_SKIPPED;
|
||||
} else if (code.equals(EBICS_TX_SEGMENT_NUMBER_UNDERRUN.code)) {
|
||||
return EBICS_DOWNLOAD_POSTPROCESS_SKIPPED;
|
||||
} else if (code.equals(EBICS_AUTHENTICATION_FAILED.code)) {
|
||||
return EBICS_AUTHENTICATION_FAILED;
|
||||
} else if (code.equals(EBICS_INVALID_REQUEST.code)) {
|
||||
return EBICS_INVALID_REQUEST;
|
||||
} else if (code.equals(EBICS_INTERNAL_ERROR.code)) {
|
||||
return EBICS_INTERNAL_ERROR;
|
||||
} else if (code.equals(EBICS_TX_RECOVERY_SYNC.code)) {
|
||||
return EBICS_TX_RECOVERY_SYNC;
|
||||
} else if (code.equals(EBICS_INVALID_USER_OR_USER_STATE.code)) {
|
||||
return EBICS_INVALID_USER_OR_USER_STATE;
|
||||
} else if (code.equals(EBICS_USER_UNKNOWN.code)) {
|
||||
return EBICS_USER_UNKNOWN;
|
||||
} else if (code.equals(EBICS_INVALID_USER_STATE.code)) {
|
||||
return EBICS_INVALID_USER_STATE;
|
||||
} else if (code.equals(EBICS_INVALID_ORDER_TYPE.code)) {
|
||||
return EBICS_INVALID_ORDER_TYPE;
|
||||
} else if (code.equals(EBICS_UNSUPPORTED_ORDER_TYPE.code)) {
|
||||
return EBICS_UNSUPPORTED_ORDER_TYPE;
|
||||
} else if (code.equals(EBICS_USER_AUTHENTICATION_REQUIRED.code)) {
|
||||
return EBICS_USER_AUTHENTICATION_REQUIRED;
|
||||
} else if (code.equals(EBICS_BANK_PUBKEY_UPDATE_REQUIRED.code)) {
|
||||
return EBICS_BANK_PUBKEY_UPDATE_REQUIRED;
|
||||
} else if (code.equals(EBICS_SEGMENT_SIZE_EXCEEDED.code)) {
|
||||
return EBICS_SEGMENT_SIZE_EXCEEDED;
|
||||
} else if (code.equals(EBICS_TX_UNKNOWN_TXID.code)) {
|
||||
return EBICS_TX_UNKNOWN_TXID;
|
||||
} else if (code.equals(EBICS_TX_ABORT.code)) {
|
||||
return EBICS_TX_ABORT;
|
||||
} else if (code.equals(EBICS_TX_MESSAGE_REPLAY.code)) {
|
||||
return EBICS_TX_MESSAGE_REPLAY;
|
||||
} else if (code.equals(EBICS_TX_SEGMENT_NUMBER_EXCEEDED.code)) {
|
||||
return EBICS_TX_SEGMENT_NUMBER_EXCEEDED;
|
||||
} else if (code.equals(EBICS_X509_CERTIFICATE_NOT_VALID_YET.code)) {
|
||||
return EBICS_X509_CERTIFICATE_NOT_VALID_YET;
|
||||
} else if (code.equals(EBICS_MAX_TRANSACTIONS_EXCEEDED.code)) {
|
||||
return EBICS_MAX_TRANSACTIONS_EXCEEDED;
|
||||
} else if (code.equals(EBICS_SIGNATURE_VERIFICATION_FAILED.code)) {
|
||||
return EBICS_SIGNATURE_VERIFICATION_FAILED;
|
||||
} else if (code.equals(EBICS_NO_DOWNLOAD_DATA_AVAILABLE.code)) {
|
||||
return EBICS_NO_DOWNLOAD_DATA_AVAILABLE;
|
||||
} else if (code.equals(EBICS_ORDER_PARAMS_IGNORED.code)) {
|
||||
return EBICS_ORDER_PARAMS_IGNORED;
|
||||
} else if (code.equals(EBICS_INVALID_XML.code)) {
|
||||
return EBICS_INVALID_XML;
|
||||
} else if (code.equals(EBICS_INVALID_HOST_ID.code)) {
|
||||
return EBICS_INVALID_HOST_ID;
|
||||
} else if (code.equals(EBICS_INVALID_ORDER_PARAMS.code)) {
|
||||
return EBICS_INVALID_ORDER_PARAMS;
|
||||
} else if (code.equals(EBICS_INVALID_REQUEST_CONTENT.code)) {
|
||||
return EBICS_INVALID_REQUEST_CONTENT;
|
||||
} else if (code.equals(EBICS_MAX_ORDER_DATA_SIZE_EXCEEDED.code)) {
|
||||
return EBICS_MAX_ORDER_DATA_SIZE_EXCEEDED;
|
||||
} else if (code.equals(EBICS_MAX_SEGMENTS_EXCEEDED.code)) {
|
||||
return EBICS_MAX_SEGMENTS_EXCEEDED;
|
||||
} else if (code.equals(EBICS_PARTNER_ID_MISMATCH.code)) {
|
||||
return EBICS_PARTNER_ID_MISMATCH;
|
||||
} else if (code.equals(EBICS_INCOMPATIBLE_ORDER_ATTRIBUTE.code)) {
|
||||
return EBICS_INCOMPATIBLE_ORDER_ATTRIBUTE;
|
||||
} else {
|
||||
return new ReturnCode(code, text, text);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof ReturnCode) {
|
||||
return this.code.equals(((ReturnCode) obj).code);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Integer.parseInt(code);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private String code;
|
||||
private String symbolicName;
|
||||
private String text;
|
||||
public static final ReturnCode EBICS_OK;
|
||||
public static final ReturnCode EBICS_DOWNLOAD_POSTPROCESS_DONE;
|
||||
public static final ReturnCode EBICS_DOWNLOAD_POSTPROCESS_SKIPPED;
|
||||
public static final ReturnCode EBICS_TX_SEGMENT_NUMBER_UNDERRUN;
|
||||
public static final ReturnCode EBICS_AUTHENTICATION_FAILED;
|
||||
public static final ReturnCode EBICS_INVALID_REQUEST;
|
||||
public static final ReturnCode EBICS_INTERNAL_ERROR;
|
||||
public static final ReturnCode EBICS_TX_RECOVERY_SYNC;
|
||||
public static final ReturnCode EBICS_INVALID_USER_OR_USER_STATE;
|
||||
public static final ReturnCode EBICS_USER_UNKNOWN;
|
||||
public static final ReturnCode EBICS_INVALID_USER_STATE;
|
||||
public static final ReturnCode EBICS_INVALID_ORDER_TYPE;
|
||||
public static final ReturnCode EBICS_UNSUPPORTED_ORDER_TYPE;
|
||||
public static final ReturnCode EBICS_USER_AUTHENTICATION_REQUIRED;
|
||||
public static final ReturnCode EBICS_BANK_PUBKEY_UPDATE_REQUIRED;
|
||||
public static final ReturnCode EBICS_SEGMENT_SIZE_EXCEEDED;
|
||||
public static final ReturnCode EBICS_TX_UNKNOWN_TXID;
|
||||
public static final ReturnCode EBICS_TX_ABORT;
|
||||
public static final ReturnCode EBICS_TX_MESSAGE_REPLAY;
|
||||
public static final ReturnCode EBICS_TX_SEGMENT_NUMBER_EXCEEDED;
|
||||
public static final ReturnCode EBICS_X509_CERTIFICATE_NOT_VALID_YET;
|
||||
public static final ReturnCode EBICS_MAX_TRANSACTIONS_EXCEEDED;
|
||||
public static final ReturnCode EBICS_SIGNATURE_VERIFICATION_FAILED;
|
||||
public static final ReturnCode EBICS_NO_DOWNLOAD_DATA_AVAILABLE;
|
||||
public static final ReturnCode EBICS_ORDER_PARAMS_IGNORED;
|
||||
public static final ReturnCode EBICS_INVALID_XML;
|
||||
public static final ReturnCode EBICS_INVALID_HOST_ID;
|
||||
public static final ReturnCode EBICS_INVALID_ORDER_PARAMS;
|
||||
public static final ReturnCode EBICS_INVALID_REQUEST_CONTENT;
|
||||
public static final ReturnCode EBICS_MAX_ORDER_DATA_SIZE_EXCEEDED;
|
||||
public static final ReturnCode EBICS_MAX_SEGMENTS_EXCEEDED;
|
||||
public static final ReturnCode EBICS_PARTNER_ID_MISMATCH;
|
||||
public static final ReturnCode EBICS_INCOMPATIBLE_ORDER_ATTRIBUTE;
|
||||
|
||||
static {
|
||||
EBICS_OK = new ReturnCode("000000", "EBICS_OK", /*$$(*/ "000000" /*)*/);
|
||||
EBICS_DOWNLOAD_POSTPROCESS_DONE =
|
||||
new ReturnCode("011000", "EBICS_DOWNLOAD_POSTPROCESS_DONE", /*$$(*/ "011000" /*)*/);
|
||||
EBICS_DOWNLOAD_POSTPROCESS_SKIPPED =
|
||||
new ReturnCode("011001", "EBICS_DOWNLOAD_POSTPROCESS_SKIPPED", /*$$(*/ "011001" /*)*/);
|
||||
EBICS_TX_SEGMENT_NUMBER_UNDERRUN =
|
||||
new ReturnCode("011101", "EBICS_TX_SEGMENT_NUMBER_UNDERRUN", /*$$(*/ "011101" /*)*/);
|
||||
EBICS_ORDER_PARAMS_IGNORED =
|
||||
new ReturnCode("031001", "EBICS_ORDER_PARAMS_IGNORED", /*$$(*/ "031001" /*)*/);
|
||||
EBICS_AUTHENTICATION_FAILED =
|
||||
new ReturnCode("061001", "EBICS_AUTHENTICATION_FAILED", /*$$(*/ "061001" /*)*/);
|
||||
EBICS_INVALID_REQUEST =
|
||||
new ReturnCode("061002", "EBICS_INVALID_REQUEST", /*$$(*/ "061002" /*)*/);
|
||||
EBICS_INTERNAL_ERROR = new ReturnCode("061099", "EBICS_INTERNAL_ERROR", /*$$(*/ "061099" /*)*/);
|
||||
EBICS_TX_RECOVERY_SYNC =
|
||||
new ReturnCode("061101", "EBICS_TX_RECOVERY_SYNC", /*$$(*/ "061101" /*)*/);
|
||||
EBICS_NO_DOWNLOAD_DATA_AVAILABLE =
|
||||
new ReturnCode("090005", "EBICS_NO_DOWNLOAD_DATA_AVAILABLE", /*$$(*/ "090005" /*)*/);
|
||||
EBICS_INVALID_USER_OR_USER_STATE =
|
||||
new ReturnCode("091002", "EBICS_INVALID_USER_OR_USER_STATE", /*$$(*/ "091002" /*)*/);
|
||||
EBICS_USER_UNKNOWN = new ReturnCode("091003", "EBICS_USER_UNKNOWN", /*$$(*/ "091003" /*)*/);
|
||||
EBICS_INVALID_USER_STATE =
|
||||
new ReturnCode("091004", "EBICS_INVALID_USER_STATE", /*$$(*/ "091004" /*)*/);
|
||||
EBICS_INVALID_ORDER_TYPE =
|
||||
new ReturnCode("091005", "EBICS_INVALID_ORDER_TYPE", /*$$(*/ "091005" /*)*/);
|
||||
EBICS_UNSUPPORTED_ORDER_TYPE =
|
||||
new ReturnCode("091006", "EBICS_UNSUPPORTED_ORDER_TYPE", /*$$(*/ "091006" /*)*/);
|
||||
EBICS_USER_AUTHENTICATION_REQUIRED =
|
||||
new ReturnCode("091007", "EBICS_USER_AUTHENTICATION_REQUIRED", /*$$(*/ "091007" /*)*/);
|
||||
EBICS_BANK_PUBKEY_UPDATE_REQUIRED =
|
||||
new ReturnCode("091008", "EBICS_BANK_PUBKEY_UPDATE_REQUIRED", /*$$(*/ "091008" /*)*/);
|
||||
EBICS_SEGMENT_SIZE_EXCEEDED =
|
||||
new ReturnCode("091009", "EBICS_SEGMENT_SIZE_EXCEEDED", /*$$(*/ "091009" /*)*/);
|
||||
EBICS_INVALID_XML = new ReturnCode("091010", "EBICS_INVALID_XML", /*$$(*/ "091010" /*)*/);
|
||||
EBICS_INVALID_HOST_ID =
|
||||
new ReturnCode("091011", "EBICS_INVALID_HOST_ID", /*$$(*/ "091011" /*)*/);
|
||||
EBICS_TX_UNKNOWN_TXID =
|
||||
new ReturnCode("091101", "EBICS_TX_UNKNOWN_TXID", /*$$(*/ "091101" /*)*/);
|
||||
EBICS_TX_ABORT = new ReturnCode("091102", "EBICS_TX_ABORT", /*$$(*/ "091102" /*)*/);
|
||||
EBICS_TX_MESSAGE_REPLAY =
|
||||
new ReturnCode("091103", "EBICS_TX_MESSAGE_REPLAY", /*$$(*/ "091103" /*)*/);
|
||||
EBICS_TX_SEGMENT_NUMBER_EXCEEDED =
|
||||
new ReturnCode("091104", "EBICS_TX_SEGMENT_NUMBER_EXCEEDED", /*$$(*/ "091104" /*)*/);
|
||||
EBICS_INVALID_ORDER_PARAMS =
|
||||
new ReturnCode("091112", "EBICS_INVALID_ORDER_PARAMS", /*$$(*/ "091112" /*)*/);
|
||||
EBICS_INVALID_REQUEST_CONTENT =
|
||||
new ReturnCode("091113", "EBICS_INVALID_REQUEST_CONTENT", /*$$(*/ "091113" /*)*/);
|
||||
EBICS_MAX_ORDER_DATA_SIZE_EXCEEDED =
|
||||
new ReturnCode("091117", "EBICS_MAX_ORDER_DATA_SIZE_EXCEEDED", /*$$(*/ "091117" /*)*/);
|
||||
EBICS_MAX_SEGMENTS_EXCEEDED =
|
||||
new ReturnCode("091118", "EBICS_MAX_SEGMENTS_EXCEEDED", /*$$(*/ "091118" /*)*/);
|
||||
EBICS_MAX_TRANSACTIONS_EXCEEDED =
|
||||
new ReturnCode("091119", "EBICS_MAX_TRANSACTIONS_EXCEEDED", /*$$(*/ "091119" /*)*/);
|
||||
EBICS_PARTNER_ID_MISMATCH =
|
||||
new ReturnCode("091120", "EBICS_PARTNER_ID_MISMATCH", /*$$(*/ "091120" /*)*/);
|
||||
EBICS_INCOMPATIBLE_ORDER_ATTRIBUTE =
|
||||
new ReturnCode("091121", "EBICS_INCOMPATIBLE_ORDER_ATTRIBUTE", /*$$(*/ "091121" /*)*/);
|
||||
EBICS_X509_CERTIFICATE_NOT_VALID_YET =
|
||||
new ReturnCode("091209", "EBICS_X509_CERTIFICATE_NOT_VALID_YET", /*$$(*/ "091209" /*)*/);
|
||||
EBICS_SIGNATURE_VERIFICATION_FAILED =
|
||||
new ReturnCode("091301", "EBICS_SIGNATURE_VERIFICATION_FAILED", /*$$(*/ "091301" /*)*/);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.interfaces;
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990-2012 kopiLeft Development SARL, Bizerte, Tunisia
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License version 2.1 as published by the Free Software Foundation.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public interface ContentFactory {
|
||||
|
||||
/**
|
||||
* Returns a new data source of the data to be sent. The instance must ensure that the returned
|
||||
* stream will deliver the identical data during the lifetime of this instance. Nevertheless how
|
||||
* often the method will be called.
|
||||
*
|
||||
* @return a new data source of the data to be sent.
|
||||
* @throws IOException
|
||||
*/
|
||||
public InputStream getContent() throws IOException;
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.io;
|
||||
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Byte array content factory that delivers the file content as a <code>ByteArrayInputStream</code>.
|
||||
* This object is serializable in a way to recover interrupted file transfers.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class ByteArrayContentFactory implements ContentFactory {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ByteArrayContentFactory</code> with a given byte array content.
|
||||
*
|
||||
* @param content the byte array content
|
||||
*/
|
||||
public ByteArrayContentFactory(byte[] content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getContent() throws IOException {
|
||||
return new ByteArrayInputStream(content);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private byte[] content;
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.io;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A simple mean to cache created files.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class FileCache {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>FileCache</code> object
|
||||
*
|
||||
* @param isTraceEnabled is trace enabled?
|
||||
*/
|
||||
public FileCache(boolean isTraceEnabled) {
|
||||
this.isTraceEnabled = isTraceEnabled;
|
||||
cache = new Hashtable<String, File>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache a new <code>java.io.File</code> in the cache buffer
|
||||
*
|
||||
* @param file the file to cache
|
||||
* @return True if the file is cached
|
||||
*/
|
||||
public boolean add(File file) {
|
||||
if (cache.containsKey(file.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cache.put(file.getName(), file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given <code>java.io.file</code> from the cache.
|
||||
*
|
||||
* @param filename the file to remove
|
||||
* @return True if the file is removed
|
||||
*/
|
||||
public boolean remove(String filename) {
|
||||
if (!cache.containsKey(filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cache.remove(filename);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Clears the cache buffer */
|
||||
public void clear() {
|
||||
if (isTraceEnabled) {
|
||||
for (File file : cache.values()) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the trace ability.
|
||||
*
|
||||
* @param enabled is trace enabled?
|
||||
*/
|
||||
public void setTraceEnabled(boolean enabled) {
|
||||
this.isTraceEnabled = enabled;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private Map<String, File> cache;
|
||||
private boolean isTraceEnabled;
|
||||
}
|
||||
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.io;
|
||||
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* Some IO utilities for EBICS files management. EBICS server
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class IOUtils {
|
||||
|
||||
/**
|
||||
* Creates a directory from a root one
|
||||
*
|
||||
* @param parent the parent directory
|
||||
* @param child the directory name
|
||||
* @return The created directory
|
||||
*/
|
||||
public static File createDirectory(File parent, String child) {
|
||||
File directory;
|
||||
|
||||
directory = new File(parent, child);
|
||||
directory.mkdir();
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a directory from a root one
|
||||
*
|
||||
* @param parent the parent directory
|
||||
* @param child the directory name
|
||||
* @return The created directory
|
||||
*/
|
||||
public static File createDirectory(String parent, String child) {
|
||||
File directory;
|
||||
|
||||
directory = new File(parent, child);
|
||||
directory.mkdir();
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a directory from a directory name
|
||||
*
|
||||
* @param name the absolute directory name
|
||||
* @return The created directory
|
||||
*/
|
||||
public static File createDirectory(String name) {
|
||||
File directory;
|
||||
|
||||
directory = new File(name);
|
||||
directory.mkdir();
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates many directories from a given full path. Path should use default separator like '/' for
|
||||
* UNIX systems
|
||||
*
|
||||
* @param fullName the full absolute path of the directories
|
||||
* @return The created directory
|
||||
*/
|
||||
public static File createDirectories(String fullName) {
|
||||
File directory;
|
||||
|
||||
directory = new File(fullName);
|
||||
directory.mkdirs();
|
||||
|
||||
return directory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>java.io.File</code> from a given root.
|
||||
*
|
||||
* @param parent the parent of the file.
|
||||
* @param name the file name.
|
||||
* @return the created file.
|
||||
*/
|
||||
public static File createFile(String parent, String name) {
|
||||
File file;
|
||||
|
||||
file = new File(parent, name);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>java.io.File</code> from a given root.
|
||||
*
|
||||
* @param parent the parent of the file.
|
||||
* @param name the file name.
|
||||
* @return the created file.
|
||||
*/
|
||||
public static File createFile(File parent, String name) {
|
||||
File file;
|
||||
|
||||
file = new File(parent, name);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a file from its name. The name can be absolute if only the directory tree is created
|
||||
*
|
||||
* @param name the file name
|
||||
* @return the created file
|
||||
*/
|
||||
public static File createFile(String name) {
|
||||
File file;
|
||||
|
||||
file = new File(name);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of a file as byte array.
|
||||
*
|
||||
* @param path the file path
|
||||
* @return the byte array content of the file
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public static byte[] getFileContent(String path) throws AxelorException {
|
||||
try {
|
||||
InputStream input;
|
||||
byte[] content;
|
||||
|
||||
input = new FileInputStream(path);
|
||||
content = new byte[input.available()];
|
||||
input.read(content);
|
||||
input.close();
|
||||
return content;
|
||||
} catch (IOException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of a <code>ContentFactory</code> as a byte array
|
||||
*
|
||||
* @param content
|
||||
* @return
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public static byte[] getFactoryContent(ContentFactory content) throws AxelorException {
|
||||
try {
|
||||
byte[] buffer;
|
||||
ByteArrayOutputStream out;
|
||||
InputStream in;
|
||||
int len = -1;
|
||||
|
||||
out = new ByteArrayOutputStream();
|
||||
in = content.getContent();
|
||||
buffer = new byte[1024];
|
||||
while ((len = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, len);
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
return out.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.io;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsUserService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
/**
|
||||
* A simple mean to join downloaded segments from the bank ebics server.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class Joiner {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>Joiner</code> object.
|
||||
*
|
||||
* @param user the ebics user.
|
||||
*/
|
||||
public Joiner(EbicsUser user) {
|
||||
this.user = user;
|
||||
buffer = new ByteArrayOutputStream();
|
||||
}
|
||||
|
||||
public void append(byte[] data) throws AxelorException {
|
||||
try {
|
||||
buffer.write(data);
|
||||
buffer.flush();
|
||||
} catch (IOException e) {
|
||||
throw new AxelorException(e.getCause(), TraceBackRepository.TYPE_TECHNICAL, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the joined part to an output stream.
|
||||
*
|
||||
* @param output the output stream.
|
||||
* @param transactionKey the transaction key
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public void writeTo(OutputStream output, byte[] transactionKey) throws AxelorException {
|
||||
try {
|
||||
byte[] decrypted;
|
||||
|
||||
buffer.close();
|
||||
decrypted =
|
||||
Beans.get(EbicsUserService.class).decrypt(user, buffer.toByteArray(), transactionKey);
|
||||
output.write(EbicsUtils.unzip(decrypted));
|
||||
output.close();
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_INCONSISTENCY, e.getMessage());
|
||||
} catch (IOException e) {
|
||||
throw new AxelorException(e.getCause(), TraceBackRepository.TYPE_TECHNICAL, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private EbicsUser user;
|
||||
private ByteArrayOutputStream buffer;
|
||||
}
|
||||
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.io;
|
||||
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* A mean to split a given input file to 1MB portions. this i useful to handle big file uploading.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class Splitter {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>FileSplitter</code> with a given file.
|
||||
*
|
||||
* @param input the input byte array
|
||||
*/
|
||||
public Splitter(byte[] input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the input stream and splits it to segments of 1MB size.
|
||||
*
|
||||
* <p>EBICS Specification 2.4.2 - 7 Segmentation of the order data:
|
||||
*
|
||||
* <p>The following procedure is to be followed with segmentation:
|
||||
*
|
||||
* <ol>
|
||||
* <li>The order data is ZIP compressed
|
||||
* <li>The compressed order data is encrypted in accordance with Chapter 6.2
|
||||
* <li>The compressed, encrypted order data is base64-coded.
|
||||
* <li>The result is to be verified with regard to the data volume:
|
||||
* <ol>
|
||||
* <li>If the resulting data volume is below the threshold of 1 MB = 1,048,576 bytes, the
|
||||
* order data can be sent complete as a data segment within one transmission step
|
||||
* <li>If the resulting data volume exceeds 1,048,576 bytes the data is to be separated
|
||||
* sequentially and in a base64-conformant manner into segments that each have a
|
||||
* maximum of 1,048,576 bytes.
|
||||
* </ol>
|
||||
*
|
||||
* @param isCompressionEnabled enable compression?
|
||||
* @param keySpec the secret key spec
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public final void readInput(boolean isCompressionEnabled, SecretKeySpec keySpec)
|
||||
throws AxelorException {
|
||||
try {
|
||||
if (isCompressionEnabled) {
|
||||
input = EbicsUtils.zip(input);
|
||||
}
|
||||
content = EbicsUtils.encrypt(input, keySpec);
|
||||
segmentation();
|
||||
} catch (Exception e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Slits the input into 1MB portions.
|
||||
*
|
||||
* <p>EBICS Specification 2.4.2 - 7 Segmentation of the order data:
|
||||
*
|
||||
* <p>In Version H003 of the EBICS standard, order data that requires more than 1 MB of storage
|
||||
* space in compressed, encrypted and base64-coded form MUST be segmented before transmission,
|
||||
* irrespective of the transfer direction (upload/download).
|
||||
*/
|
||||
private void segmentation() {
|
||||
|
||||
numSegments = content.length / 1048576; // (1024 * 1024)
|
||||
|
||||
if (content.length % 1048576 != 0) {
|
||||
numSegments++;
|
||||
}
|
||||
|
||||
segmentSize = content.length / numSegments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of a data segment according to a given segment number.
|
||||
*
|
||||
* @param segmentNumber the segment number
|
||||
* @return
|
||||
*/
|
||||
public ContentFactory getContent(int segmentNumber) {
|
||||
byte[] segment;
|
||||
int offset;
|
||||
|
||||
offset = segmentSize * (segmentNumber - 1);
|
||||
if (content.length < segmentSize + offset) {
|
||||
segment = new byte[content.length - offset];
|
||||
} else {
|
||||
segment = new byte[segmentSize];
|
||||
}
|
||||
|
||||
System.arraycopy(content, offset, segment, 0, segment.length);
|
||||
return new ByteArrayContentFactory(segment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hole content.
|
||||
*
|
||||
* @return the input content.
|
||||
*/
|
||||
public byte[] getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total segment number.
|
||||
*
|
||||
* @return the total segment number.
|
||||
*/
|
||||
public int getSegmentNumber() {
|
||||
return numSegments;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private byte[] input;
|
||||
private byte[] content;
|
||||
private int segmentSize;
|
||||
private int numSegments;
|
||||
}
|
||||
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.script;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsBank;
|
||||
import com.axelor.apps.bankpayment.db.EbicsCertificate;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsCertificateService;
|
||||
import com.axelor.apps.base.db.Bank;
|
||||
import com.axelor.apps.base.service.BankService;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.IOException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Map;
|
||||
|
||||
public class EbicsUserImport {
|
||||
|
||||
@Inject private EbicsCertificateService certificateService;
|
||||
|
||||
@Inject private BankService bankService;
|
||||
|
||||
public Object importEbicsUser(Object bean, Map<String, Object> context) {
|
||||
|
||||
assert bean instanceof EbicsUser;
|
||||
|
||||
EbicsUser user = (EbicsUser) bean;
|
||||
|
||||
updateCertificate(user.getA005Certificate());
|
||||
updateCertificate(user.getE002Certificate());
|
||||
updateCertificate(user.getX002Certificate());
|
||||
|
||||
EbicsPartner partner = user.getEbicsPartner();
|
||||
if (partner != null) {
|
||||
EbicsBank ebicsBank = partner.getEbicsBank();
|
||||
if (ebicsBank.getVersion() == 0) {
|
||||
for (EbicsCertificate cert : ebicsBank.getEbicsCertificateList()) {
|
||||
updateCertificate(cert);
|
||||
}
|
||||
Bank bank = ebicsBank.getBank();
|
||||
if (bank.getVersion() == 0) {
|
||||
bankService.computeFullName(bank);
|
||||
bankService.splitBic(bank);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
private void updateCertificate(EbicsCertificate cert) {
|
||||
|
||||
if (cert == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String pem = cert.getPemString();
|
||||
if (pem == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
X509Certificate certificate = certificateService.convertToCertificate(pem);
|
||||
certificateService.updateCertificate(certificate, cert, false);
|
||||
} catch (IOException | CertificateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.service;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsBank;
|
||||
|
||||
public interface EbicsBankService {
|
||||
|
||||
public void computeFullName(EbicsBank ebicsBank);
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.service;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsBank;
|
||||
|
||||
public class EbicsBankServiceImpl implements EbicsBankService {
|
||||
|
||||
@Override
|
||||
public void computeFullName(EbicsBank ebicsBank) {
|
||||
ebicsBank.setFullName(ebicsBank.getBank().getFullName());
|
||||
ebicsBank.setName(ebicsBank.getBank().getBankName());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.service;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsBank;
|
||||
import com.axelor.apps.bankpayment.db.EbicsCertificate;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsCertificateRepository;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.apps.tool.date.DateTool;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.MetaStore;
|
||||
import com.axelor.meta.schema.views.Selection.Option;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.StringReader;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.net.URL;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
|
||||
import org.bouncycastle.openssl.PEMParser;
|
||||
import org.bouncycastle.openssl.PEMWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class EbicsCertificateService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
@Inject private EbicsCertificateRepository certRepo;
|
||||
|
||||
@Inject private AppBaseService appBaseService;
|
||||
|
||||
public static byte[] getCertificateContent(EbicsBank bank, String type) throws AxelorException {
|
||||
|
||||
EbicsCertificate cert = getEbicsCertificate(bank, type);
|
||||
|
||||
if (cert != null) {
|
||||
return cert.getCertificate();
|
||||
}
|
||||
|
||||
if (bank.getUrl() != null && type.equals(EbicsCertificateRepository.TYPE_SSL)) {
|
||||
return Beans.get(EbicsCertificateService.class).getSSLCertificate(bank);
|
||||
}
|
||||
|
||||
throw new AxelorException(
|
||||
bank,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get("No bank certificate of type %s found"),
|
||||
type);
|
||||
}
|
||||
|
||||
public static X509Certificate getCertificate(byte[] certificate, String type)
|
||||
throws AxelorException {
|
||||
|
||||
ByteArrayInputStream instream = new ByteArrayInputStream(certificate);
|
||||
X509Certificate cert;
|
||||
try {
|
||||
cert =
|
||||
(X509Certificate)
|
||||
CertificateFactory.getInstance("X.509", "BC").generateCertificate(instream);
|
||||
} catch (CertificateException | NoSuchProviderException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(),
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get("Error in bank certificate of type %s"),
|
||||
type);
|
||||
}
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
public static X509Certificate getBankCertificate(EbicsBank bank, String type)
|
||||
throws AxelorException {
|
||||
|
||||
byte[] certificate = getCertificateContent(bank, type);
|
||||
|
||||
if (certificate == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getCertificate(certificate, type);
|
||||
}
|
||||
|
||||
private byte[] getSSLCertificate(EbicsBank bank) throws AxelorException {
|
||||
|
||||
try {
|
||||
final URL bankUrl = new URL(bank.getUrl());
|
||||
log.debug("Bank url protocol: {}", bankUrl.getProtocol());
|
||||
log.debug("Bank url host: {}", bankUrl.getHost());
|
||||
log.debug("Bank url port: {}", bankUrl.getPort());
|
||||
|
||||
String urlStr = bankUrl.getProtocol() + "://" + bankUrl.getHost();
|
||||
|
||||
if (bankUrl.getPort() > -1) {
|
||||
urlStr += ":" + bankUrl.getPort();
|
||||
}
|
||||
|
||||
final URL url = new URL(urlStr);
|
||||
|
||||
SSLContext sslCtx = SSLContext.getInstance("TLS");
|
||||
sslCtx.init(
|
||||
null,
|
||||
new TrustManager[] {
|
||||
new X509TrustManager() {
|
||||
|
||||
private X509Certificate[] accepted;
|
||||
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] arg0, String arg1)
|
||||
throws CertificateException {}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] arg0, String arg1)
|
||||
throws CertificateException {
|
||||
accepted = arg0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return accepted;
|
||||
}
|
||||
}
|
||||
},
|
||||
null);
|
||||
|
||||
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
|
||||
|
||||
HttpsURLConnection.setDefaultHostnameVerifier(
|
||||
new HostnameVerifier() {
|
||||
|
||||
@Override
|
||||
public boolean verify(String arg0, SSLSession arg1) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
connection.setSSLSocketFactory(sslCtx.getSocketFactory());
|
||||
log.debug("SSL connection response code: {}", connection.getResponseCode());
|
||||
log.debug("SSL connection response message: {}", connection.getResponseMessage());
|
||||
|
||||
if (connection.getResponseCode() == 200) {
|
||||
Certificate[] certificates = connection.getServerCertificates();
|
||||
for (int i = 0; i < certificates.length; i++) {
|
||||
Certificate certificate = certificates[i];
|
||||
if (certificate instanceof X509Certificate) {
|
||||
X509Certificate cert = (X509Certificate) certificate;
|
||||
createCertificate(cert, bank, EbicsCertificateRepository.TYPE_SSL);
|
||||
return certificate.getEncoded();
|
||||
}
|
||||
}
|
||||
}
|
||||
connection.disconnect();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
// throw new AxelorException(I18n.get("Error in getting ssl certificate"),
|
||||
// TraceBackRepository.CATEGORY_CONFIGURATION_ERROR);
|
||||
|
||||
}
|
||||
|
||||
public EbicsCertificate updateCertificate(
|
||||
X509Certificate certificate, EbicsCertificate cert, boolean cleanPrivateKey)
|
||||
throws CertificateEncodingException, IOException {
|
||||
|
||||
String sha = DigestUtils.sha256Hex(certificate.getEncoded());
|
||||
log.debug("sha256 HEX : {}", sha);
|
||||
log.debug("certificat : {}", new String(certificate.getEncoded()));
|
||||
log.debug("certificat size : {}", certificate.getEncoded().length);
|
||||
|
||||
cert.setValidFrom(DateTool.toLocalDate(certificate.getNotBefore()));
|
||||
cert.setValidTo(DateTool.toLocalDate(certificate.getNotAfter()));
|
||||
cert.setIssuer(certificate.getIssuerDN().getName());
|
||||
cert.setSubject(certificate.getSubjectDN().getName());
|
||||
cert.setCertificate(certificate.getEncoded());
|
||||
RSAPublicKey publicKey = (RSAPublicKey) certificate.getPublicKey();
|
||||
cert.setPublicKeyExponent(publicKey.getPublicExponent().toString(16));
|
||||
cert.setPublicKeyModulus(publicKey.getModulus().toString(16));
|
||||
cert.setSerial(certificate.getSerialNumber().toString(16));
|
||||
cert.setPemString(convertToPEMString(certificate));
|
||||
|
||||
if (cleanPrivateKey) {
|
||||
cert.setPrivateKey(null);
|
||||
}
|
||||
|
||||
sha = sha.toUpperCase();
|
||||
cert.setSha2has(sha);
|
||||
computeFullName(cert);
|
||||
|
||||
return cert;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public EbicsCertificate createCertificate(
|
||||
X509Certificate certificate, EbicsBank bank, String type)
|
||||
throws CertificateEncodingException, IOException {
|
||||
|
||||
EbicsCertificate cert = getEbicsCertificate(bank, type);
|
||||
if (cert == null) {
|
||||
log.debug("Creating bank certicate for bank: {}, type: {}", bank.getName(), type);
|
||||
cert = new EbicsCertificate();
|
||||
cert.setEbicsBank(bank);
|
||||
cert.setTypeSelect(type);
|
||||
}
|
||||
|
||||
cert = updateCertificate(certificate, cert, true);
|
||||
|
||||
return certRepo.save(cert);
|
||||
}
|
||||
|
||||
private static EbicsCertificate getEbicsCertificate(EbicsBank bank, String type) {
|
||||
|
||||
if (bank == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (EbicsCertificate cert : bank.getEbicsCertificateList()) {
|
||||
if (cert.getTypeSelect().equals(type)) {
|
||||
return cert;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void computeFullName(EbicsCertificate entity) {
|
||||
|
||||
StringBuilder fullName = new StringBuilder();
|
||||
Option item =
|
||||
MetaStore.getSelectionItem(
|
||||
"bankpayment.ebics.certificate.type.select", entity.getTypeSelect());
|
||||
if (item != null) {
|
||||
fullName.append(I18n.get(item.getTitle()));
|
||||
}
|
||||
|
||||
LocalDate date = entity.getValidFrom();
|
||||
if (date != null) {
|
||||
fullName.append(":" + date.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
|
||||
date = entity.getValidTo();
|
||||
if (date != null) {
|
||||
fullName.append("-" + date.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
|
||||
}
|
||||
}
|
||||
|
||||
String issuer = entity.getIssuer();
|
||||
if (issuer != null) {
|
||||
fullName.append(":" + issuer);
|
||||
}
|
||||
|
||||
entity.setFullName(fullName.toString());
|
||||
}
|
||||
|
||||
public String convertToPEMString(X509Certificate x509Cert) throws IOException {
|
||||
|
||||
StringWriter sw = new StringWriter();
|
||||
try (PEMWriter pw = new PEMWriter(sw)) {
|
||||
pw.writeObject(x509Cert);
|
||||
}
|
||||
|
||||
return sw.toString();
|
||||
}
|
||||
|
||||
public X509Certificate convertToCertificate(String pemString)
|
||||
throws IOException, CertificateException {
|
||||
|
||||
X509Certificate certificate;
|
||||
StringReader reader = new StringReader(pemString);
|
||||
try (final PEMParser pr = new PEMParser(reader)) {
|
||||
final X509CertificateHolder certificateHolder = (X509CertificateHolder) pr.readObject();
|
||||
certificate = new JcaX509CertificateConverter().getCertificate(certificateHolder);
|
||||
}
|
||||
|
||||
return certificate;
|
||||
}
|
||||
|
||||
public byte[] convertToDER(String pemString) throws IOException, CertificateException {
|
||||
|
||||
X509Certificate cert = convertToCertificate(pemString);
|
||||
|
||||
return cert.getEncoded();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void updateEditionDate(EbicsUser user) {
|
||||
|
||||
LocalDateTime now = appBaseService.getTodayDateTime().toLocalDateTime();
|
||||
|
||||
EbicsCertificate certificate = user.getA005Certificate();
|
||||
if (certificate != null) {
|
||||
certificate.setInitLetterEditionDate(now);
|
||||
certRepo.save(certificate);
|
||||
}
|
||||
|
||||
certificate = user.getE002Certificate();
|
||||
if (certificate != null) {
|
||||
certificate.setInitLetterEditionDate(now);
|
||||
certRepo.save(certificate);
|
||||
}
|
||||
|
||||
certificate = user.getX002Certificate();
|
||||
if (certificate != null) {
|
||||
certificate.setInitLetterEditionDate(now);
|
||||
certRepo.save(certificate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.service;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankStatement;
|
||||
import com.axelor.apps.bankpayment.db.BankStatementFileFormat;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface EbicsPartnerService {
|
||||
|
||||
List<BankStatement> getBankStatements(EbicsPartner ebicsPartner)
|
||||
throws AxelorException, IOException;
|
||||
|
||||
List<BankStatement> getBankStatements(
|
||||
EbicsPartner ebicsPartner,
|
||||
Collection<BankStatementFileFormat> bankStatementFileFormatCollection)
|
||||
throws AxelorException, IOException;
|
||||
|
||||
/**
|
||||
* Check if bank details miss mandatory currency
|
||||
*
|
||||
* @param ebicsPartner
|
||||
* @throws AxelorException with the name of the bank details missing currency if the currency is
|
||||
* mandatory
|
||||
*/
|
||||
void checkBankDetailsMissingCurrency(EbicsPartner ebicsPartner) throws AxelorException;
|
||||
}
|
||||
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.service;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankStatement;
|
||||
import com.axelor.apps.bankpayment.db.BankStatementFileFormat;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankStatementRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsPartnerRepository;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.bankpayment.service.bankstatement.BankStatementCreateService;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.tool.date.DateTool;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.common.base.Function;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class EbicsPartnerServiceImpl implements EbicsPartnerService {
|
||||
|
||||
protected BankStatementCreateService bankStatementCreateService;
|
||||
protected EbicsService ebicsService;
|
||||
protected BankStatementRepository bankStatementRepository;
|
||||
|
||||
@Inject
|
||||
public EbicsPartnerServiceImpl(
|
||||
BankStatementCreateService bankStatementCreateService,
|
||||
EbicsService ebicsService,
|
||||
BankStatementRepository bankStatementRepository) {
|
||||
|
||||
this.bankStatementCreateService = bankStatementCreateService;
|
||||
this.ebicsService = ebicsService;
|
||||
this.bankStatementRepository = bankStatementRepository;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<BankStatement> getBankStatements(EbicsPartner ebicsPartner)
|
||||
throws AxelorException, IOException {
|
||||
return getBankStatements(ebicsPartner, null);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<BankStatement> getBankStatements(
|
||||
EbicsPartner ebicsPartner,
|
||||
Collection<BankStatementFileFormat> bankStatementFileFormatCollection)
|
||||
throws AxelorException, IOException {
|
||||
|
||||
List<BankStatement> bankStatementList = Lists.newArrayList();
|
||||
|
||||
EbicsUser transportEbicsUser = ebicsPartner.getTransportEbicsUser();
|
||||
|
||||
if (ebicsPartner.getBsEbicsPartnerServiceList() == null
|
||||
|| ebicsPartner.getBsEbicsPartnerServiceList().isEmpty()
|
||||
|| transportEbicsUser == null) {
|
||||
return bankStatementList;
|
||||
}
|
||||
|
||||
LocalDateTime executionDateTime = LocalDateTime.now();
|
||||
|
||||
Date startDate = null;
|
||||
Date endDate = null;
|
||||
LocalDate bankStatementStartDate = null;
|
||||
LocalDate bankStatementToDate = null;
|
||||
|
||||
if (ebicsPartner.getBankStatementGetModeSelect() == EbicsPartnerRepository.GET_MODE_PERIOD) {
|
||||
bankStatementStartDate = ebicsPartner.getBankStatementStartDate();
|
||||
if (bankStatementStartDate != null) {
|
||||
startDate = DateTool.toDate(bankStatementStartDate);
|
||||
}
|
||||
bankStatementToDate = ebicsPartner.getBankStatementEndDate();
|
||||
if (bankStatementToDate != null) {
|
||||
endDate = DateTool.toDate(bankStatementToDate);
|
||||
}
|
||||
} else {
|
||||
if (ebicsPartner.getBankStatementLastExeDateT() != null) {
|
||||
bankStatementStartDate = ebicsPartner.getBankStatementLastExeDateT().toLocalDate();
|
||||
}
|
||||
bankStatementToDate = executionDateTime.toLocalDate();
|
||||
}
|
||||
|
||||
for (com.axelor.apps.bankpayment.db.EbicsPartnerService bsEbicsPartnerService :
|
||||
ebicsPartner.getBsEbicsPartnerServiceList()) {
|
||||
|
||||
BankStatementFileFormat bankStatementFileFormat =
|
||||
bsEbicsPartnerService.getBankStatementFileFormat();
|
||||
if (bankStatementFileFormatCollection != null
|
||||
&& !bankStatementFileFormatCollection.isEmpty()
|
||||
&& !bankStatementFileFormatCollection.contains(bankStatementFileFormat)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
File file =
|
||||
ebicsService.sendFDLRequest(
|
||||
transportEbicsUser,
|
||||
null,
|
||||
startDate,
|
||||
endDate,
|
||||
bsEbicsPartnerService.getEbicsCodification());
|
||||
|
||||
BankStatement bankStatement =
|
||||
bankStatementCreateService.createBankStatement(
|
||||
file,
|
||||
bankStatementStartDate,
|
||||
bankStatementToDate,
|
||||
bankStatementFileFormat,
|
||||
ebicsPartner,
|
||||
executionDateTime);
|
||||
|
||||
bankStatementRepository.save(bankStatement);
|
||||
|
||||
bankStatementList.add(bankStatement);
|
||||
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
}
|
||||
|
||||
ebicsPartner.setBankStatementLastExeDateT(executionDateTime);
|
||||
|
||||
Beans.get(EbicsPartnerRepository.class).save(ebicsPartner);
|
||||
|
||||
return bankStatementList;
|
||||
}
|
||||
|
||||
public void checkBankDetailsMissingCurrency(EbicsPartner ebicsPartner) throws AxelorException {
|
||||
List<com.axelor.apps.bankpayment.db.EbicsPartnerService> ebicsPartnerServiceSet =
|
||||
ebicsPartner.getBoEbicsPartnerServiceList();
|
||||
if (ebicsPartnerServiceSet == null) {
|
||||
return;
|
||||
}
|
||||
boolean allowOrderCurrDiffFromBankDetails = false;
|
||||
for (com.axelor.apps.bankpayment.db.EbicsPartnerService ebicsPartnerService :
|
||||
ebicsPartnerServiceSet) {
|
||||
allowOrderCurrDiffFromBankDetails =
|
||||
allowOrderCurrDiffFromBankDetails
|
||||
|| ebicsPartnerService
|
||||
.getBankOrderFileFormat()
|
||||
.getAllowOrderCurrDiffFromBankDetails();
|
||||
if (allowOrderCurrDiffFromBankDetails) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!allowOrderCurrDiffFromBankDetails) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<BankDetails> bankDetailsSet = ebicsPartner.getBankDetailsSet();
|
||||
if (bankDetailsSet == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> bankDetailsWithoutCurrency = new ArrayList<>();
|
||||
for (BankDetails bankDetails : bankDetailsSet) {
|
||||
if (bankDetails.getCurrency() == null) {
|
||||
bankDetailsWithoutCurrency.add(bankDetails.getFullName());
|
||||
}
|
||||
}
|
||||
|
||||
if (!bankDetailsWithoutCurrency.isEmpty()) {
|
||||
Function<String, String> addLi =
|
||||
new Function<String, String>() {
|
||||
@Override
|
||||
public String apply(String s) {
|
||||
return "<li>".concat(s).concat("</li>").toString();
|
||||
}
|
||||
};
|
||||
|
||||
throw new AxelorException(
|
||||
String.format(
|
||||
I18n.get(IExceptionMessage.EBICS_PARTNER_BANK_DETAILS_WARNING),
|
||||
"<ul>"
|
||||
+ Joiner.on("").join(Iterables.transform(bankDetailsWithoutCurrency, addLi))
|
||||
+ "<ul>"),
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
ebicsPartner);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,489 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.service;
|
||||
|
||||
import com.axelor.app.AppSettings;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderFileFormat;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartnerService;
|
||||
import com.axelor.apps.bankpayment.db.EbicsRequestLog;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsPartnerRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsRequestLogRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsUserRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsProduct;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.FileTransfer;
|
||||
import com.axelor.apps.bankpayment.ebics.client.KeyManagement;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.apps.bankpayment.ebics.io.IOUtils;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.PKCS8EncodedKeySpec;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.jdom.JDOMException;
|
||||
|
||||
public class EbicsService {
|
||||
|
||||
@Inject private EbicsUserRepository userRepo;
|
||||
|
||||
@Inject private EbicsRequestLogRepository logRepo;
|
||||
|
||||
@Inject private EbicsUserService userService;
|
||||
|
||||
@Inject private MetaFiles metaFiles;
|
||||
|
||||
private EbicsProduct defaultProduct;
|
||||
|
||||
static {
|
||||
org.apache.xml.security.Init.init();
|
||||
java.security.Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
@Inject
|
||||
public EbicsService() {
|
||||
|
||||
AppSettings settings = AppSettings.get();
|
||||
String name = settings.get("application.name") + " " + settings.get("application.version");
|
||||
String language = settings.get("application.locale");
|
||||
String instituteID = settings.get("application.author");
|
||||
|
||||
defaultProduct = new EbicsProduct(name, language, instituteID);
|
||||
}
|
||||
|
||||
public String makeDN(EbicsUser ebicsUser) {
|
||||
|
||||
String email = null;
|
||||
String companyName = defaultProduct.getInstituteID();
|
||||
User user = ebicsUser.getAssociatedUser();
|
||||
|
||||
if (user != null) {
|
||||
email = user.getEmail();
|
||||
if (user.getActiveCompany() != null) {
|
||||
companyName = user.getActiveCompany().getName();
|
||||
}
|
||||
}
|
||||
|
||||
return makeDN(ebicsUser.getName(), email, "FR", companyName);
|
||||
}
|
||||
|
||||
private String makeDN(String name, String email, String country, String organization) {
|
||||
|
||||
StringBuffer buffer = new StringBuffer();
|
||||
buffer.append("CN=" + name);
|
||||
|
||||
if (country != null) {
|
||||
buffer.append(", " + "C=" + country.toUpperCase());
|
||||
}
|
||||
if (organization != null) {
|
||||
buffer.append(", " + "O=" + organization);
|
||||
}
|
||||
if (email != null) {
|
||||
buffer.append(", " + "E=" + email);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
public RSAPublicKey getPublicKey(String modulus, String exponent)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
|
||||
RSAPublicKeySpec spec = new RSAPublicKeySpec(new BigInteger(modulus), new BigInteger(exponent));
|
||||
KeyFactory factory = KeyFactory.getInstance("RSA");
|
||||
RSAPublicKey pub = (RSAPublicKey) factory.generatePublic(spec);
|
||||
/*Signature verifier = Signature.getInstance("SHA1withRSA");
|
||||
verifier.initVerify(pub);
|
||||
boolean okay = verifier.verify(signature);*/
|
||||
|
||||
return pub;
|
||||
}
|
||||
|
||||
public RSAPrivateKey getPrivateKey(byte[] encoded)
|
||||
throws NoSuchAlgorithmException, InvalidKeySpecException {
|
||||
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
|
||||
KeyFactory kf = KeyFactory.getInstance("RSA");
|
||||
return (RSAPrivateKey) kf.generatePrivate(keySpec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends an INI request to the ebics bank server
|
||||
*
|
||||
* @param userId the user ID
|
||||
* @param product the application product
|
||||
* @throws AxelorException
|
||||
* @throws JDOMException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Transactional
|
||||
public void sendINIRequest(EbicsUser ebicsUser, EbicsProduct product) throws AxelorException {
|
||||
|
||||
if (ebicsUser.getStatusSelect()
|
||||
!= EbicsUserRepository.STATUS_WAITING_SENDING_SIGNATURE_CERTIFICATE) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
userService.getNextOrderId(ebicsUser);
|
||||
EbicsSession session = new EbicsSession(ebicsUser);
|
||||
if (product == null) {
|
||||
product = defaultProduct;
|
||||
}
|
||||
session.setProduct(product);
|
||||
|
||||
KeyManagement keyManager = new KeyManagement(session);
|
||||
keyManager.sendINI();
|
||||
|
||||
ebicsUser.setStatusSelect(EbicsUserRepository.STATUS_WAITING_AUTH_AND_ENCRYPT_CERTIFICATES);
|
||||
userRepo.save(ebicsUser);
|
||||
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
throw new AxelorException(e, TraceBackRepository.TYPE_TECHNICAL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a HIA request to the ebics server.
|
||||
*
|
||||
* @param userId the user ID.
|
||||
* @param product the application product.
|
||||
* @throws AxelorException
|
||||
*/
|
||||
@Transactional
|
||||
public void sendHIARequest(EbicsUser ebicsUser, EbicsProduct product) throws AxelorException {
|
||||
|
||||
if (ebicsUser.getStatusSelect()
|
||||
!= EbicsUserRepository.STATUS_WAITING_AUTH_AND_ENCRYPT_CERTIFICATES) {
|
||||
return;
|
||||
}
|
||||
userService.getNextOrderId(ebicsUser);
|
||||
|
||||
EbicsSession session = new EbicsSession(ebicsUser);
|
||||
if (product == null) {
|
||||
product = defaultProduct;
|
||||
}
|
||||
session.setProduct(product);
|
||||
KeyManagement keyManager = new KeyManagement(session);
|
||||
|
||||
try {
|
||||
keyManager.sendHIA();
|
||||
ebicsUser.setStatusSelect(EbicsUserRepository.STATUS_ACTIVE_CONNECTION);
|
||||
userRepo.save(ebicsUser);
|
||||
} catch (IOException | AxelorException | JDOMException e) {
|
||||
TraceBackService.trace(e);
|
||||
throw new AxelorException(e, TraceBackRepository.TYPE_TECHNICAL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a HPB request to the ebics server.
|
||||
*
|
||||
* @param userId the user ID.
|
||||
* @param product the application product.
|
||||
* @throws AxelorException
|
||||
*/
|
||||
@Transactional
|
||||
public X509Certificate[] sendHPBRequest(EbicsUser user, EbicsProduct product)
|
||||
throws AxelorException {
|
||||
|
||||
EbicsSession session = new EbicsSession(user);
|
||||
if (product == null) {
|
||||
product = defaultProduct;
|
||||
}
|
||||
session.setProduct(product);
|
||||
|
||||
KeyManagement keyManager = new KeyManagement(session);
|
||||
try {
|
||||
return keyManager.sendHPB();
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
throw new AxelorException(e, TraceBackRepository.TYPE_TECHNICAL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the SPR order to the bank.
|
||||
*
|
||||
* @param userId the user ID
|
||||
* @param product the session product
|
||||
* @throws AxelorException
|
||||
*/
|
||||
@Transactional
|
||||
public void sendSPRRequest(EbicsUser ebicsUser, EbicsProduct product) throws AxelorException {
|
||||
|
||||
EbicsSession session = new EbicsSession(ebicsUser);
|
||||
if (product == null) {
|
||||
product = defaultProduct;
|
||||
}
|
||||
session.setProduct(product);
|
||||
|
||||
KeyManagement keyManager = new KeyManagement(session);
|
||||
try {
|
||||
keyManager.lockAccess();
|
||||
ebicsUser.setStatusSelect(EbicsUserRepository.STATUS_WAITING_SENDING_SIGNATURE_CERTIFICATE);
|
||||
userService.getNextOrderId(ebicsUser);
|
||||
userRepo.save(ebicsUser);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
throw new AxelorException(e, TraceBackRepository.TYPE_TECHNICAL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a file to the EBICS bank server.
|
||||
*
|
||||
* @param transportUser
|
||||
* @param signatoryUser
|
||||
* @param product
|
||||
* @param file
|
||||
* @param format
|
||||
* @param signature
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public void sendFULRequest(
|
||||
EbicsUser transportUser,
|
||||
EbicsUser signatoryUser,
|
||||
EbicsProduct product,
|
||||
File file,
|
||||
BankOrderFileFormat format,
|
||||
File signature)
|
||||
throws AxelorException {
|
||||
Preconditions.checkNotNull(transportUser);
|
||||
Preconditions.checkNotNull(transportUser.getEbicsPartner());
|
||||
Preconditions.checkNotNull(format);
|
||||
List<EbicsPartnerService> ebicsPartnerServiceList =
|
||||
transportUser.getEbicsPartner().getBoEbicsPartnerServiceList();
|
||||
String ebicsCodification;
|
||||
|
||||
if (ebicsPartnerServiceList == null || ebicsPartnerServiceList.isEmpty()) {
|
||||
ebicsCodification = format.getOrderFileFormatSelect();
|
||||
} else {
|
||||
ebicsCodification = findEbicsCodification(transportUser.getEbicsPartner(), format);
|
||||
}
|
||||
|
||||
sendFULRequest(transportUser, signatoryUser, product, file, ebicsCodification, signature);
|
||||
}
|
||||
|
||||
private String findEbicsCodification(EbicsPartner ebicsPartner, BankOrderFileFormat format)
|
||||
throws AxelorException {
|
||||
Preconditions.checkNotNull(ebicsPartner);
|
||||
Preconditions.checkNotNull(format);
|
||||
|
||||
if (ebicsPartner.getBoEbicsPartnerServiceList() != null) {
|
||||
for (EbicsPartnerService service : ebicsPartner.getBoEbicsPartnerServiceList()) {
|
||||
if (format.equals(service.getBankOrderFileFormat())) {
|
||||
return service.getEbicsCodification();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new AxelorException(
|
||||
I18n.get(IExceptionMessage.EBICS_NO_SERVICE_CONFIGURED),
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
ebicsPartner.getPartnerId(),
|
||||
format.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a file to the ebics bank sever
|
||||
*
|
||||
* @param path the file path to send
|
||||
* @param userId the user ID that sends the file.
|
||||
* @param product the application product.
|
||||
* @throws AxelorException
|
||||
*/
|
||||
private void sendFULRequest(
|
||||
EbicsUser transportUser,
|
||||
EbicsUser signatoryUser,
|
||||
EbicsProduct product,
|
||||
File file,
|
||||
String format,
|
||||
File signature)
|
||||
throws AxelorException {
|
||||
|
||||
EbicsSession session = new EbicsSession(transportUser, signatoryUser);
|
||||
boolean test = isTest(transportUser);
|
||||
if (test) {
|
||||
session.addSessionParam("TEST", "true");
|
||||
}
|
||||
if (file == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, "File is required to send FUL request");
|
||||
}
|
||||
EbicsPartner ebicsPartner = transportUser.getEbicsPartner();
|
||||
|
||||
if (ebicsPartner.getEbicsTypeSelect() == EbicsPartnerRepository.EBICS_TYPE_TS) {
|
||||
if (signature == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
"Signature file is required to send FUL request");
|
||||
}
|
||||
if (signatoryUser == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
"Signatory user is required to send FUL request");
|
||||
}
|
||||
}
|
||||
|
||||
session.addSessionParam("EBCDIC", "false");
|
||||
session.addSessionParam("FORMAT", format);
|
||||
|
||||
if (product == null) {
|
||||
product = defaultProduct;
|
||||
}
|
||||
session.setProduct(product);
|
||||
FileTransfer transferManager = new FileTransfer(session);
|
||||
|
||||
try {
|
||||
if (ebicsPartner.getEbicsTypeSelect() == EbicsPartnerRepository.EBICS_TYPE_TS) {
|
||||
transferManager.sendFile(
|
||||
IOUtils.getFileContent(file.getAbsolutePath()),
|
||||
OrderType.FUL,
|
||||
IOUtils.getFileContent(signature.getAbsolutePath()));
|
||||
} else {
|
||||
transferManager.sendFile(
|
||||
IOUtils.getFileContent(file.getAbsolutePath()), OrderType.FUL, null);
|
||||
}
|
||||
userService.getNextOrderId(transportUser);
|
||||
} catch (IOException | AxelorException e) {
|
||||
TraceBackService.trace(e);
|
||||
throw new AxelorException(e, TraceBackRepository.TYPE_TECHNICAL);
|
||||
}
|
||||
|
||||
try {
|
||||
if (ebicsPartner.getUsePSR()) {
|
||||
sendFDLRequest(
|
||||
transportUser,
|
||||
product,
|
||||
null,
|
||||
null,
|
||||
ebicsPartner.getpSRBankStatementFileFormat().getStatementFileFormatSelect());
|
||||
}
|
||||
} catch (AxelorException e) {
|
||||
TraceBackService.trace(e);
|
||||
}
|
||||
}
|
||||
|
||||
public File sendFDLRequest(
|
||||
EbicsUser user, EbicsProduct product, Date start, Date end, String fileFormat)
|
||||
throws AxelorException {
|
||||
|
||||
return fetchFile(OrderType.FDL, user, product, start, end, fileFormat);
|
||||
}
|
||||
|
||||
public File sendHTDRequest(EbicsUser user, EbicsProduct product, Date start, Date end)
|
||||
throws AxelorException {
|
||||
|
||||
return fetchFile(OrderType.HTD, user, product, start, end, null);
|
||||
}
|
||||
|
||||
public File sendPTKRequest(EbicsUser user, EbicsProduct product, Date start, Date end)
|
||||
throws AxelorException {
|
||||
|
||||
return fetchFile(OrderType.PTK, user, product, start, end, null);
|
||||
}
|
||||
|
||||
public File sendHPDRequest(EbicsUser user, EbicsProduct product, Date start, Date end)
|
||||
throws AxelorException {
|
||||
|
||||
return fetchFile(OrderType.HPD, user, product, start, end, null);
|
||||
}
|
||||
|
||||
private File fetchFile(
|
||||
OrderType orderType,
|
||||
EbicsUser user,
|
||||
EbicsProduct product,
|
||||
Date start,
|
||||
Date end,
|
||||
String fileFormat)
|
||||
throws AxelorException {
|
||||
|
||||
EbicsSession session = new EbicsSession(user);
|
||||
File file = null;
|
||||
try {
|
||||
boolean test = isTest(user);
|
||||
if (test) {
|
||||
session.addSessionParam("TEST", "true");
|
||||
}
|
||||
if (fileFormat != null) {
|
||||
session.addSessionParam("FORMAT", fileFormat);
|
||||
}
|
||||
if (product == null) {
|
||||
product = defaultProduct;
|
||||
}
|
||||
session.setProduct(product);
|
||||
|
||||
FileTransfer transferManager = new FileTransfer(session);
|
||||
|
||||
file = File.createTempFile(user.getName(), "." + orderType.getOrderType());
|
||||
transferManager.fetchFile(orderType, start, end, new FileOutputStream(file));
|
||||
|
||||
addResponseFile(user, file);
|
||||
|
||||
userService.getNextOrderId(user);
|
||||
|
||||
} catch (AxelorException e) {
|
||||
TraceBackService.trace(e);
|
||||
throw e;
|
||||
} catch (IOException e) {
|
||||
TraceBackService.trace(e);
|
||||
throw new AxelorException(e, TraceBackRepository.TYPE_TECHNICAL);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
private boolean isTest(EbicsUser user) throws AxelorException {
|
||||
|
||||
EbicsPartner partner = user.getEbicsPartner();
|
||||
|
||||
return partner.getTestMode();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void addResponseFile(EbicsUser user, File file) throws IOException {
|
||||
|
||||
EbicsRequestLog requestLog =
|
||||
logRepo.all().filter("self.ebicsUser = ?1", user).order("-id").fetchOne();
|
||||
if (requestLog != null && file != null && file.length() > 0) {
|
||||
requestLog.setResponseFile(metaFiles.upload(file));
|
||||
logRepo.save(requestLog);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,342 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.service;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.EbicsRequestLog;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsRequestLogRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsUserRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsRootElement;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.Signature;
|
||||
import java.time.LocalDateTime;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.jdom.JDOMException;
|
||||
|
||||
public class EbicsUserService {
|
||||
|
||||
@Inject private EbicsService ebicsService;
|
||||
|
||||
@Inject private EbicsRequestLogRepository requestLogRepo;
|
||||
|
||||
@Inject private EbicsUserRepository ebicsUserRepo;
|
||||
|
||||
/**
|
||||
* EBICS Specification 2.4.2 - 14.1 Version A005/A006 of the electronic signature:
|
||||
*
|
||||
* <p>For the signature processes A005 an interval of 1536 bit (minimum) and 4096 bit (maximum) is
|
||||
* defined for the key length.
|
||||
*
|
||||
* <p>The digital signature mechanisms A005 is both based on the industry standard [PKCS1] using
|
||||
* the hash algorithm SHA-256. They are both signature mechanisms without message recovery.
|
||||
*
|
||||
* <p>A hash algorithm maps bit sequences of arbitrary length (input bit sequences) to byte
|
||||
* sequences of a fixed length, determined by the Hash algorithm. The result of the execution of a
|
||||
* Hash algorithm to a bit sequence is defined as hash value.
|
||||
*
|
||||
* <p>The hash algorithm SHA-256 is specified in [FIPS H2]. SHA-256 maps input bit sequences of
|
||||
* arbitrary length to byte sequences of 32 byte length. The padding of input bit sequences to a
|
||||
* length being a multiple of 64 byte is part of the hash algorithm. The padding even is applied
|
||||
* if the input bit sequence already has a length that is a multiple of 64 byte.
|
||||
*
|
||||
* <p>SHA-256 processes the input bit sequences in blocks of 64 byte length. The hash value of a
|
||||
* bit sequence x under the hash algorithm SHA-256 is referred to as follows: SHA-256(x).
|
||||
*
|
||||
* <p>The digital signature mechanism A005 is identical to EMSA-PKCS1-v1_5 using the hash
|
||||
* algorithm SHA-256. The byte length H of the hash value is 32.
|
||||
*
|
||||
* <p>According [PKCS1] (using the method EMSA-PKCS1-v1_5) the following steps shall be performed
|
||||
* for the computation of a signature for message M with bit length m.
|
||||
*
|
||||
* <ol>
|
||||
* <li>The hash value HASH(M) of the byte length H shall be computed. In the case of A005
|
||||
* SHA-256(M) with a length of 32 bytes.
|
||||
* <li>The DSI for the signature algorithm shall be generated.
|
||||
* <li>A signature shall be computed using the DSI with the standard algorithm for the signature
|
||||
* generation described in section 14.1.3.1 of the EBICS specification (V 2.4.2).
|
||||
* </ol>
|
||||
*
|
||||
* <p>The {@link Signature} is a digital signature scheme with appendix (SSA) combining the RSA
|
||||
* algorithm with the EMSA-PKCS1-v1_5 encoding method.
|
||||
*
|
||||
* <p>The {@code digest} will be signed with the RSA user signature key using the {@link
|
||||
* Signature} that will be instantiated with the <b>SHA-256</b> algorithm. This signature is then
|
||||
* put in a {@link UserSignature} XML object that will be sent to the EBICS server.
|
||||
*/
|
||||
public byte[] sign(EbicsUser ebicsUser, byte[] digest)
|
||||
throws IOException, GeneralSecurityException {
|
||||
|
||||
Signature signature =
|
||||
Signature.getInstance("SHA256WithRSA", BouncyCastleProvider.PROVIDER_NAME);
|
||||
signature.initSign(ebicsService.getPrivateKey(ebicsUser.getA005Certificate().getPrivateKey()));
|
||||
signature.update(removeOSSpecificChars(digest));
|
||||
return signature.sign();
|
||||
}
|
||||
|
||||
/**
|
||||
* EBICS Specification 2.4.2 - 11.1.1 Process:
|
||||
*
|
||||
* <p>Identification and authentication signatures are based on the RSA signature process. The
|
||||
* following parameters determine the identification and authentication signature process:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Length of the (secret) RSA key
|
||||
* <li>Hash algorithm
|
||||
* <li>Padding process
|
||||
* <li>Canonisation process.
|
||||
* </ol>
|
||||
*
|
||||
* <p>For the identification and authentication process, EBICS defines the process “X002” with the
|
||||
* following parameters:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Key length in Kbit >=1Kbit (1024 bit) and lesser than 16Kbit
|
||||
* <li>Hash algorithm SHA-256
|
||||
* <li>Padding process: PKCS#1
|
||||
* <li>Canonisation process: http://www.w3.org/TR/2001/REC-xml-c14n-20010315
|
||||
* </ol>
|
||||
*
|
||||
* <p>From EBICS 2.4 on, the customer system must use the hash value of the public bank key X002
|
||||
* in a request.
|
||||
*
|
||||
* <p>Notes:
|
||||
*
|
||||
* <ol>
|
||||
* <li>The key length is defined else where.
|
||||
* <li>The padding is performed by the {@link Signature} class.
|
||||
* <li>The digest is already canonized in the {@link SignedInfo#sign(byte[]) sign(byte[])}
|
||||
* </ol>
|
||||
*/
|
||||
public byte[] authenticate(EbicsUser ebicsUser, byte[] digest) throws GeneralSecurityException {
|
||||
Signature signature;
|
||||
signature = Signature.getInstance("SHA256WithRSA", BouncyCastleProvider.PROVIDER_NAME);
|
||||
signature.initSign(ebicsService.getPrivateKey(ebicsUser.getX002Certificate().getPrivateKey()));
|
||||
signature.update(digest);
|
||||
return signature.sign();
|
||||
}
|
||||
|
||||
/**
|
||||
* EBICS Specification 2.4.2 - 7.1 Process description:
|
||||
*
|
||||
* <p>In particular, so-called “white-space characters” such as spaces, tabs, carriage returns and
|
||||
* line feeds (“CR/LF”) are not permitted.
|
||||
*
|
||||
* <p>All white-space characters should be removed from entry buffer {@code buf}.
|
||||
*
|
||||
* @param buf the given byte buffer
|
||||
* @param offset the offset
|
||||
* @param length the length
|
||||
* @return The byte buffer portion corresponding to the given length and offset
|
||||
*/
|
||||
public static byte[] removeOSSpecificChars(byte[] content) {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
for (byte b : content) {
|
||||
switch (b) {
|
||||
case '\r':
|
||||
case '\n':
|
||||
case 0x1A: // CTRL-Z / EOF
|
||||
// ignore this characters
|
||||
break;
|
||||
default:
|
||||
output.write(b);
|
||||
}
|
||||
}
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* EBICS IG CFONB VF 2.1.4 2012 02 24 - 2.1.3.2 Calcul de la signature:
|
||||
*
|
||||
* <p>Il convient d’utiliser PKCS1 V1.5 pour chiffrer la clé de chiffrement.
|
||||
*
|
||||
* <p>EBICS Specification 2.4.2 - 15.2 Workflows at the recipient’s end:
|
||||
*
|
||||
* <p><b>Decryption of the DES key</b>
|
||||
*
|
||||
* <p>The leading 256 null bits of the EDEK are removed and the remaining 768 bits are decrypted
|
||||
* with the recipient’s secret key of the RSA key system. PDEK is then present. The secret DES key
|
||||
* DEK is obtained from the lowest-value 128 bits of PDEK, this is split into the individual keys
|
||||
* DEK<SUB>left</SUB> and DEK<SUB>right</SUB>.
|
||||
*/
|
||||
public byte[] decrypt(EbicsUser user, byte[] encryptedData, byte[] transactionKey)
|
||||
throws AxelorException, GeneralSecurityException, IOException {
|
||||
Cipher cipher;
|
||||
int blockSize;
|
||||
ByteArrayOutputStream outputStream;
|
||||
|
||||
cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding", BouncyCastleProvider.PROVIDER_NAME);
|
||||
cipher.init(
|
||||
Cipher.DECRYPT_MODE, ebicsService.getPrivateKey(user.getE002Certificate().getPrivateKey()));
|
||||
blockSize = cipher.getBlockSize();
|
||||
outputStream = new ByteArrayOutputStream();
|
||||
for (int j = 0; j * blockSize < transactionKey.length; j++) {
|
||||
outputStream.write(cipher.doFinal(transactionKey, j * blockSize, blockSize));
|
||||
}
|
||||
|
||||
return decryptData(encryptedData, outputStream.toByteArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts the <code>encryptedData</code> using the decoded transaction key.
|
||||
*
|
||||
* <p>EBICS Specification 2.4.2 - 15.2 Workflows at the recipient’s end:
|
||||
*
|
||||
* <p><b>Decryption of the message</b>
|
||||
*
|
||||
* <p>The encrypted original message is decrypted in CBC mode in accordance with the 2-key triple
|
||||
* DES process via the secret DES key (comprising DEK<SUB>left</SUB> and DEK<SUP>right<SUB>). In
|
||||
* doing this, the following initialization value ICV is again used.
|
||||
*
|
||||
* <p><b>Removal of the padding information</b>
|
||||
*
|
||||
* <p>The method “Padding with Octets” according to ANSI X9.23 is used to remove the padding
|
||||
* information from the decrypted message. The original message is then available in decrypted
|
||||
* form.
|
||||
*
|
||||
* @param input The encrypted data
|
||||
* @param key The secret key.
|
||||
* @return The decrypted data sent from the EBICS bank.
|
||||
* @throws GeneralSecurityException
|
||||
* @throws IOException
|
||||
*/
|
||||
private byte[] decryptData(byte[] input, byte[] key) throws AxelorException {
|
||||
return EbicsUtils.decrypt(input, new SecretKeySpec(key, "EAS"));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void logRequest(
|
||||
long ebicsUserId, String requestType, String responseCode, EbicsRootElement[] rootElements) {
|
||||
|
||||
EbicsRequestLog requestLog = new EbicsRequestLog();
|
||||
requestLog.setEbicsUser(ebicsUserRepo.find(ebicsUserId));
|
||||
LocalDateTime time = LocalDateTime.now();
|
||||
requestLog.setRequestTime(time);
|
||||
requestLog.setRequestType(requestType);
|
||||
requestLog.setResponseCode(responseCode);
|
||||
|
||||
try {
|
||||
trace(requestLog, rootElements);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
requestLogRepo.save(requestLog);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public String getNextOrderId(EbicsUser user) throws AxelorException {
|
||||
|
||||
String orderId = user.getNextOrderId();
|
||||
|
||||
if (orderId == null) {
|
||||
EbicsPartner partner = user.getEbicsPartner();
|
||||
EbicsUser otherUser =
|
||||
ebicsUserRepo
|
||||
.all()
|
||||
.filter(
|
||||
"self.ebicsPartner = ?1 and self.id != ?2 and self.nextOrderId != null",
|
||||
partner,
|
||||
user.getId())
|
||||
.order("-nextOrderId")
|
||||
.fetchOne();
|
||||
|
||||
char firstLetter = 'A';
|
||||
if (otherUser != null) {
|
||||
String otherOrderId = otherUser.getNextOrderId();
|
||||
firstLetter = otherOrderId.charAt(0);
|
||||
firstLetter++;
|
||||
}
|
||||
|
||||
orderId = String.valueOf(firstLetter) + "000";
|
||||
user.setNextOrderId(orderId);
|
||||
ebicsUserRepo.save(user);
|
||||
} else {
|
||||
orderId = getNextOrderNumber(orderId);
|
||||
user.setNextOrderId(orderId);
|
||||
ebicsUserRepo.save(user);
|
||||
}
|
||||
|
||||
return orderId;
|
||||
}
|
||||
|
||||
public String getNextOrderNumber(String orderId) throws AxelorException {
|
||||
|
||||
if (Strings.isNullOrEmpty(orderId) || orderId.matches("[^a-z0-9 ]") || orderId.length() != 4) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD, I18n.get("Invalid order id \"%s\""), orderId);
|
||||
}
|
||||
|
||||
if (orderId.substring(1).equals("ZZZ")) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD, I18n.get("Maximum order limit reach"));
|
||||
}
|
||||
|
||||
char[] orderIds = orderId.toCharArray();
|
||||
|
||||
if (orderIds[3] != 'Z') {
|
||||
orderIds[3] = getNextChar(orderIds[3]);
|
||||
} else {
|
||||
orderIds[3] = '0';
|
||||
if (orderIds[2] != 'Z') {
|
||||
orderIds[2] = getNextChar(orderIds[2]);
|
||||
} else {
|
||||
orderIds[2] = '0';
|
||||
if (orderIds[1] != 'Z') {
|
||||
orderIds[1] = getNextChar(orderIds[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new String(orderIds);
|
||||
}
|
||||
|
||||
private char getNextChar(char c) {
|
||||
|
||||
if (c == '9') {
|
||||
return 'A';
|
||||
}
|
||||
|
||||
return (char) ((int) c + 1);
|
||||
}
|
||||
|
||||
private void trace(EbicsRequestLog requestLog, EbicsRootElement[] rootElements)
|
||||
throws AxelorException, JDOMException, IOException {
|
||||
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
rootElements[0].save(bout);
|
||||
requestLog.setRequestTraceText(bout.toString());
|
||||
bout.close();
|
||||
|
||||
bout = new ByteArrayOutputStream();
|
||||
rootElements[1].save(bout);
|
||||
requestLog.setResponseTraceText(bout.toString());
|
||||
bout.close();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,519 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.web;
|
||||
|
||||
import com.axelor.apps.ReportFactory;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderFileFormat;
|
||||
import com.axelor.apps.bankpayment.db.BankStatementFileFormat;
|
||||
import com.axelor.apps.bankpayment.db.EbicsBank;
|
||||
import com.axelor.apps.bankpayment.db.EbicsCertificate;
|
||||
import com.axelor.apps.bankpayment.db.EbicsRequestLog;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsBankRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsCertificateRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsPartnerRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsRequestLogRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsUserRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.certificate.CertificateManager;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsCertificateService;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsService;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.bankpayment.report.IReport;
|
||||
import com.axelor.apps.report.engine.ReportSettings;
|
||||
import com.axelor.data.Listener;
|
||||
import com.axelor.data.xml.XMLImporter;
|
||||
import com.axelor.db.Model;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.axelor.meta.db.MetaFile;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.axelor.rpc.Context;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.xmlbeans.impl.common.IOUtil;
|
||||
|
||||
@Singleton
|
||||
public class EbicsController {
|
||||
|
||||
private static int totalRecord = 0, importedRecord = 0;
|
||||
|
||||
@Transactional
|
||||
public void generateCertificate(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
if (ebicsUser.getStatusSelect() != EbicsUserRepository.STATUS_WAITING_CERTIFICATE_CONFIG
|
||||
&& ebicsUser.getStatusSelect()
|
||||
!= EbicsUserRepository.STATUS_CERTIFICATES_SHOULD_BE_RENEWED) {
|
||||
return;
|
||||
}
|
||||
|
||||
CertificateManager cm = new CertificateManager(ebicsUser);
|
||||
try {
|
||||
cm.create();
|
||||
ebicsUser.setStatusSelect(EbicsUserRepository.STATUS_WAITING_SENDING_SIGNATURE_CERTIFICATE);
|
||||
Beans.get(EbicsUserRepository.class).save(ebicsUser);
|
||||
} catch (GeneralSecurityException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
public void generateDn(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
response.setValue("dn", Beans.get(EbicsService.class).makeDN(ebicsUser));
|
||||
}
|
||||
|
||||
public void sendINIRequest(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
try {
|
||||
Beans.get(EbicsService.class).sendINIRequest(ebicsUser, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
response.setFlash(stripClass(e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
public void sendHIARequest(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
try {
|
||||
Beans.get(EbicsService.class).sendHIARequest(ebicsUser, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
response.setFlash(stripClass(e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
public void sendHPBRequest(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
try {
|
||||
X509Certificate[] certificates =
|
||||
Beans.get(EbicsService.class).sendHPBRequest(ebicsUser, null);
|
||||
confirmCertificates(ebicsUser, certificates, response);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
response.setFlash(stripClass(e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
private void confirmCertificates(
|
||||
EbicsUser user, X509Certificate[] certificates, ActionResponse response) {
|
||||
|
||||
try {
|
||||
EbicsBank bank = user.getEbicsPartner().getEbicsBank();
|
||||
response.setView(
|
||||
ActionView.define("Confirm certificates")
|
||||
.model("com.axelor.apps.bankpayment.db.EbicsCertificate")
|
||||
.add("form", "ebics-certificate-confirmation-form")
|
||||
.param("show-toolbar", "false")
|
||||
.param("show-confirm", "false")
|
||||
.param("popup-save", "false")
|
||||
.param("popup", "true")
|
||||
.context("ebicsBank", bank)
|
||||
.context("url", bank.getUrl())
|
||||
.context("hostId", bank.getHostId())
|
||||
.context(
|
||||
"e002Hash", DigestUtils.sha256Hex(certificates[0].getEncoded()).toUpperCase())
|
||||
.context(
|
||||
"x002Hash", DigestUtils.sha256Hex(certificates[1].getEncoded()).toUpperCase())
|
||||
.context(
|
||||
"certificateE002",
|
||||
Beans.get(EbicsCertificateService.class).convertToPEMString(certificates[0]))
|
||||
.context(
|
||||
"certificateX002",
|
||||
Beans.get(EbicsCertificateService.class).convertToPEMString(certificates[1]))
|
||||
.map());
|
||||
} catch (Exception e) {
|
||||
response.setFlash("Error in certificate confirmation ");
|
||||
}
|
||||
}
|
||||
|
||||
public void sendSPRRequest(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
try {
|
||||
Beans.get(EbicsService.class).sendSPRRequest(ebicsUser, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
response.setFlash(stripClass(e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
public void sendFULRequest(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
try {
|
||||
|
||||
MetaFile testDataMetaFile = ebicsUser.getTestDataFile();
|
||||
MetaFile testSignatureMetaFile = ebicsUser.getTestSignatureFile();
|
||||
|
||||
BankOrderFileFormat bankOrderFileFormat = ebicsUser.getTestBankOrderFileFormat();
|
||||
|
||||
if (testDataMetaFile != null && bankOrderFileFormat != null) {
|
||||
|
||||
File testSignatureFile = null;
|
||||
|
||||
if (ebicsUser.getEbicsPartner().getEbicsTypeSelect() == EbicsPartnerRepository.EBICS_TYPE_TS
|
||||
&& testSignatureMetaFile != null) {
|
||||
testSignatureFile = MetaFiles.getPath(testSignatureMetaFile).toFile();
|
||||
}
|
||||
|
||||
Beans.get(EbicsService.class)
|
||||
.sendFULRequest(
|
||||
ebicsUser,
|
||||
ebicsUser.getTestSignatoryEbicsUser(),
|
||||
null,
|
||||
MetaFiles.getPath(testDataMetaFile).toFile(),
|
||||
bankOrderFileFormat,
|
||||
testSignatureFile);
|
||||
} else {
|
||||
response.setFlash(I18n.get(IExceptionMessage.EBICS_TEST_MODE_NOT_ENABLED));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
response.setFlash(stripClass(e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
public void sendFDLRequest(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
try {
|
||||
|
||||
BankStatementFileFormat bankStatementFileFormat = ebicsUser.getTestBankStatementFileFormat();
|
||||
|
||||
if (ebicsUser.getEbicsPartner().getTestMode() && bankStatementFileFormat != null) {
|
||||
Beans.get(EbicsService.class)
|
||||
.sendFDLRequest(
|
||||
ebicsUser,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
bankStatementFileFormat.getStatementFileFormatSelect());
|
||||
downloadFile(response, ebicsUser);
|
||||
} else {
|
||||
response.setFlash(I18n.get(IExceptionMessage.EBICS_TEST_MODE_NOT_ENABLED));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
response.setFlash(stripClass(e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
public void sendHTDRequest(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
try {
|
||||
Beans.get(EbicsService.class).sendHTDRequest(ebicsUser, null, null, null);
|
||||
downloadFile(response, ebicsUser);
|
||||
} catch (Exception e) {
|
||||
response.setFlash(stripClass(e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
public void sendPTKRequest(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
try {
|
||||
Beans.get(EbicsService.class).sendPTKRequest(ebicsUser, null, null, null);
|
||||
downloadFile(response, ebicsUser);
|
||||
} catch (Exception e) {
|
||||
response.setFlash(stripClass(e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
public void sendHPDRequest(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser =
|
||||
Beans.get(EbicsUserRepository.class)
|
||||
.find(request.getContext().asType(EbicsUser.class).getId());
|
||||
|
||||
try {
|
||||
Beans.get(EbicsService.class).sendHPDRequest(ebicsUser, null, null, null);
|
||||
downloadFile(response, ebicsUser);
|
||||
} catch (Exception e) {
|
||||
response.setFlash(stripClass(e.getLocalizedMessage()));
|
||||
}
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
private String stripClass(String msg) {
|
||||
|
||||
return msg.replace(AxelorException.class.getName() + ":", "");
|
||||
}
|
||||
|
||||
public void addCertificates(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
|
||||
Context context = request.getContext();
|
||||
|
||||
EbicsBank ebicsBank = (EbicsBank) context.get("ebicsBank");
|
||||
|
||||
ebicsBank = Beans.get(EbicsBankRepository.class).find(ebicsBank.getId());
|
||||
|
||||
try {
|
||||
X509Certificate certificate =
|
||||
Beans.get(EbicsCertificateService.class)
|
||||
.convertToCertificate((String) context.get("certificateE002"));
|
||||
Beans.get(EbicsCertificateService.class)
|
||||
.createCertificate(certificate, ebicsBank, EbicsCertificateRepository.TYPE_ENCRYPTION);
|
||||
|
||||
certificate =
|
||||
Beans.get(EbicsCertificateService.class)
|
||||
.convertToCertificate((String) context.get("certificateX002"));
|
||||
Beans.get(EbicsCertificateService.class)
|
||||
.createCertificate(
|
||||
certificate, ebicsBank, EbicsCertificateRepository.TYPE_AUTHENTICATION);
|
||||
|
||||
} catch (CertificateException | IOException e) {
|
||||
e.printStackTrace();
|
||||
throw new AxelorException(
|
||||
e,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get("Error in adding bank certificate"));
|
||||
}
|
||||
|
||||
response.setCanClose(true);
|
||||
}
|
||||
|
||||
public void loadCertificate(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException, CertificateEncodingException, IOException {
|
||||
|
||||
EbicsCertificate ebicsCertificate = request.getContext().asType(EbicsCertificate.class);
|
||||
|
||||
ebicsCertificate = Beans.get(EbicsCertificateRepository.class).find(ebicsCertificate.getId());
|
||||
|
||||
byte[] certs = ebicsCertificate.getCertificate();
|
||||
|
||||
if (certs != null && certs.length > 0) {
|
||||
X509Certificate certificate =
|
||||
EbicsCertificateService.getCertificate(certs, ebicsCertificate.getTypeSelect());
|
||||
ebicsCertificate =
|
||||
Beans.get(EbicsCertificateService.class)
|
||||
.updateCertificate(certificate, ebicsCertificate, true);
|
||||
response.setValue("validFrom", ebicsCertificate.getValidFrom());
|
||||
response.setValue("validTo", ebicsCertificate.getValidTo());
|
||||
response.setValue("issuer", ebicsCertificate.getIssuer());
|
||||
response.setValue("subject", ebicsCertificate.getSubject());
|
||||
response.setValue("publicKeyModulus", ebicsCertificate.getPublicKeyModulus());
|
||||
response.setValue("publicKeyExponent", ebicsCertificate.getPublicKeyExponent());
|
||||
response.setValue("fullName", ebicsCertificate.getFullName());
|
||||
response.setValue("pemString", ebicsCertificate.getPemString());
|
||||
response.setValue("sha2has", ebicsCertificate.getSha2has());
|
||||
}
|
||||
}
|
||||
|
||||
public void updateEditionDate(ActionRequest request, ActionResponse response) {
|
||||
|
||||
EbicsUser ebicsUser = request.getContext().asType(EbicsUser.class);
|
||||
ebicsUser = Beans.get(EbicsUserRepository.class).find(ebicsUser.getId());
|
||||
Beans.get(EbicsCertificateService.class).updateEditionDate(ebicsUser);
|
||||
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void importEbicsUsers(ActionRequest request, ActionResponse response) {
|
||||
|
||||
String config = "/data-import/import-ebics-user-config.xml";
|
||||
|
||||
try {
|
||||
InputStream inputStream = this.getClass().getResourceAsStream(config);
|
||||
File configFile = File.createTempFile("config", ".xml");
|
||||
FileOutputStream fout = new FileOutputStream(configFile);
|
||||
IOUtil.copyCompletely(inputStream, fout);
|
||||
|
||||
Path path =
|
||||
MetaFiles.getPath((String) ((Map) request.getContext().get("dataFile")).get("filePath"));
|
||||
File tempDir = Files.createTempDir();
|
||||
File importFile = new File(tempDir, "ebics-user.xml");
|
||||
Files.copy(path.toFile(), importFile);
|
||||
|
||||
totalRecord = importedRecord = 0;
|
||||
XMLImporter importer =
|
||||
new XMLImporter(configFile.getAbsolutePath(), tempDir.getAbsolutePath());
|
||||
final StringBuilder log = new StringBuilder();
|
||||
|
||||
Listener listner =
|
||||
new Listener() {
|
||||
|
||||
@Override
|
||||
public void imported(Integer imported, Integer total) {}
|
||||
|
||||
@Override
|
||||
public void imported(Model arg0) {
|
||||
if (arg0.getClass().isAssignableFrom(EbicsUser.class)) {
|
||||
totalRecord++;
|
||||
importedRecord++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Model arg0, Exception err) {
|
||||
TraceBackService.trace(err);
|
||||
if (arg0.getClass().isAssignableFrom(EbicsUser.class)) {
|
||||
totalRecord++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
importer.addListener(listner);
|
||||
|
||||
importer.run();
|
||||
|
||||
FileUtils.forceDelete(configFile);
|
||||
|
||||
FileUtils.forceDelete(tempDir);
|
||||
log.append("Total records: " + totalRecord + ", Total imported: " + importedRecord);
|
||||
response.setValue("importLog", log.toString());
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void printCertificates(ActionRequest request, ActionResponse response)
|
||||
throws AxelorException {
|
||||
|
||||
EbicsUser ebicsUser = request.getContext().asType(EbicsUser.class);
|
||||
|
||||
ArrayList<Long> certIds = new ArrayList<Long>();
|
||||
if (ebicsUser.getA005Certificate() != null) {
|
||||
certIds.add(ebicsUser.getA005Certificate().getId());
|
||||
}
|
||||
if (ebicsUser.getE002Certificate() != null) {
|
||||
certIds.add(ebicsUser.getE002Certificate().getId());
|
||||
}
|
||||
if (ebicsUser.getX002Certificate() != null) {
|
||||
certIds.add(ebicsUser.getX002Certificate().getId());
|
||||
}
|
||||
|
||||
if (certIds.isEmpty()) {
|
||||
throw new AxelorException(
|
||||
ebicsUser,
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get(IExceptionMessage.EBICS_MISSING_CERTIFICATES));
|
||||
}
|
||||
|
||||
String title = I18n.get("EbicsCertificate");
|
||||
|
||||
ReportSettings report =
|
||||
ReportFactory.createReport(IReport.EBICS_CERTIFICATE, title + "-${date}${time}");
|
||||
report.addParam("CertificateId", Joiner.on(",").join(certIds));
|
||||
report.addParam("EbicsUserId", ebicsUser.getId());
|
||||
report.toAttach(ebicsUser);
|
||||
report.generate();
|
||||
|
||||
response.setView(ActionView.define(title).add("html", report.getFileLink()).map());
|
||||
}
|
||||
|
||||
private void downloadFile(ActionResponse response, EbicsUser user) {
|
||||
|
||||
EbicsRequestLog requestLog =
|
||||
Beans.get(EbicsRequestLogRepository.class)
|
||||
.all()
|
||||
.filter("self.ebicsUser = ?1", user)
|
||||
.order("-id")
|
||||
.fetchOne();
|
||||
|
||||
if (requestLog != null && requestLog.getResponseFile() != null) {
|
||||
response.setView(
|
||||
ActionView.define(requestLog.getRequestType())
|
||||
.add(
|
||||
"html",
|
||||
"ws/rest/"
|
||||
+ EbicsRequestLog.class.getCanonicalName()
|
||||
+ "/"
|
||||
+ requestLog.getId()
|
||||
+ "/responseFile/download")
|
||||
.param("download", "dtrue")
|
||||
.map());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.web;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankStatement;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsPartnerRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsPartnerService;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
import com.google.inject.Singleton;
|
||||
import java.util.List;
|
||||
|
||||
@Singleton
|
||||
public class EbicsPartnerController {
|
||||
|
||||
public void getBankStatement(ActionRequest request, ActionResponse response) {
|
||||
|
||||
try {
|
||||
EbicsPartner ebicsPartner = request.getContext().asType(EbicsPartner.class);
|
||||
List<BankStatement> bankStatementList =
|
||||
Beans.get(EbicsPartnerService.class)
|
||||
.getBankStatements(
|
||||
Beans.get(EbicsPartnerRepository.class).find(ebicsPartner.getId()));
|
||||
response.setFlash(
|
||||
String.format(I18n.get("%s bank statements get."), bankStatementList.size()));
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
response.setReload(true);
|
||||
}
|
||||
|
||||
public void checkBankDetailsSet(ActionRequest request, ActionResponse response) {
|
||||
EbicsPartner ebicsPartner = request.getContext().asType(EbicsPartner.class);
|
||||
try {
|
||||
Beans.get(EbicsPartnerService.class).checkBankDetailsMissingCurrency(ebicsPartner);
|
||||
} catch (Exception e) {
|
||||
response.setFlash(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.web;
|
||||
|
||||
import com.axelor.apps.ReportFactory;
|
||||
import com.axelor.apps.bankpayment.db.EbicsRequestLog;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsRequestLogRepository;
|
||||
import com.axelor.apps.report.engine.ReportSettings;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.rpc.ActionRequest;
|
||||
import com.axelor.rpc.ActionResponse;
|
||||
|
||||
public class EbicsRequestLogController {
|
||||
|
||||
public void print(ActionRequest request, ActionResponse response) {
|
||||
try {
|
||||
EbicsRequestLog ebicsRequestLog = request.getContext().asType(EbicsRequestLog.class);
|
||||
ebicsRequestLog = Beans.get(EbicsRequestLogRepository.class).find(ebicsRequestLog.getId());
|
||||
|
||||
String name = "Ebics report log " + ebicsRequestLog.getRequestType();
|
||||
|
||||
String fileLink =
|
||||
ReportFactory.createReport("EbicsReportLog.rptdesign", name + "-${date}")
|
||||
.addParam("EbicsReportLogId", ebicsRequestLog.getId())
|
||||
.addParam("Locale", ReportSettings.getPrintingLocale(null))
|
||||
.addFormat("pdf")
|
||||
.toAttach(ebicsRequestLog)
|
||||
.generate()
|
||||
.getFileLink();
|
||||
|
||||
response.setView(ActionView.define(name).add("html", fileLink).map());
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(response, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Body;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Header;
|
||||
import com.axelor.apps.account.ebics.schema.h003.FDLOrderParamsType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.FDLOrderParamsType.DateRange;
|
||||
import com.axelor.apps.account.ebics.schema.h003.FileFormatType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.MutableHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.ParameterDocument.Parameter;
|
||||
import com.axelor.apps.account.ebics.schema.h003.ParameterDocument.Parameter.Value;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StandardOrderParamsType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderOrderDetailsType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderOrderDetailsType.OrderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.BankPubKeyDigests;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.BankPubKeyDigests.Authentication;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.BankPubKeyDigests.Encryption;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.Product;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.certificate.KeyUtil;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderAttribute;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* The <code>DInitializationRequestElement</code> is the common initialization for all ebics
|
||||
* downloads.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class DInitializationRequestElement extends InitializationRequestElement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>DInitializationRequestElement</code> for downloads initializations.
|
||||
*
|
||||
* @param session the current ebics session
|
||||
* @param type the download order type (FDL, HTD, HPD)
|
||||
* @param startRange the start range download
|
||||
* @param endRange the end range download
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public DInitializationRequestElement(
|
||||
EbicsSession session,
|
||||
com.axelor.apps.bankpayment.ebics.client.OrderType type,
|
||||
Date startRange,
|
||||
Date endRange)
|
||||
throws AxelorException {
|
||||
super(session, type, generateName(type));
|
||||
this.startRange = startRange;
|
||||
this.endRange = endRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildInitialization() throws AxelorException {
|
||||
EbicsRequest request;
|
||||
Header header;
|
||||
Body body;
|
||||
MutableHeaderType mutable;
|
||||
StaticHeaderType xstatic;
|
||||
Product product;
|
||||
BankPubKeyDigests bankPubKeyDigests;
|
||||
Authentication authentication;
|
||||
Encryption encryption;
|
||||
OrderType orderType;
|
||||
StaticHeaderOrderDetailsType orderDetails;
|
||||
|
||||
mutable = EbicsXmlFactory.createMutableHeaderType("Initialisation", null);
|
||||
product =
|
||||
EbicsXmlFactory.createProduct(
|
||||
session.getProduct().getLanguage(), session.getProduct().getName());
|
||||
authentication =
|
||||
EbicsXmlFactory.createAuthentication(
|
||||
"X002",
|
||||
"http://www.w3.org/2001/04/xmlenc#sha256",
|
||||
decodeHex(KeyUtil.getKeyDigest(session.getBankX002Key())));
|
||||
encryption =
|
||||
EbicsXmlFactory.createEncryption(
|
||||
"E002",
|
||||
"http://www.w3.org/2001/04/xmlenc#sha256",
|
||||
decodeHex(KeyUtil.getKeyDigest(session.getBankE002Key())));
|
||||
bankPubKeyDigests = EbicsXmlFactory.createBankPubKeyDigests(authentication, encryption);
|
||||
orderType = EbicsXmlFactory.createOrderType(type.getOrderType());
|
||||
|
||||
EbicsUser ebicsUser = session.getUser();
|
||||
EbicsPartner ebicsPartner = ebicsUser.getEbicsPartner();
|
||||
|
||||
OrderAttribute orderAttribute = new OrderAttribute(type, ebicsPartner.getEbicsTypeSelect());
|
||||
orderAttribute.build();
|
||||
|
||||
if (type.equals(com.axelor.apps.bankpayment.ebics.client.OrderType.FDL)) {
|
||||
FDLOrderParamsType fDLOrderParamsType;
|
||||
FileFormatType fileFormat;
|
||||
|
||||
fileFormat =
|
||||
EbicsXmlFactory.createFileFormatType(
|
||||
Locale.FRANCE.getCountry().toUpperCase(), session.getSessionParam("FORMAT"));
|
||||
fDLOrderParamsType = EbicsXmlFactory.createFDLOrderParamsType(fileFormat);
|
||||
|
||||
if (startRange != null && endRange != null) {
|
||||
DateRange range;
|
||||
range = EbicsXmlFactory.createDateRange(startRange, endRange);
|
||||
fDLOrderParamsType.setDateRange(range);
|
||||
}
|
||||
|
||||
if (Boolean.getBoolean(session.getSessionParam("TEST"))) {
|
||||
Parameter parameter;
|
||||
Value value;
|
||||
|
||||
value = EbicsXmlFactory.createValue("String", "TRUE");
|
||||
parameter = EbicsXmlFactory.createParameter("TEST", value);
|
||||
fDLOrderParamsType.setParameterArray(new Parameter[] {parameter});
|
||||
}
|
||||
orderDetails =
|
||||
EbicsXmlFactory.createStaticHeaderOrderDetailsType(
|
||||
ebicsUser.getNextOrderId(),
|
||||
orderAttribute.getOrderAttributes(),
|
||||
orderType,
|
||||
fDLOrderParamsType);
|
||||
} else {
|
||||
StandardOrderParamsType standardOrderParamsType;
|
||||
|
||||
standardOrderParamsType = EbicsXmlFactory.createStandardOrderParamsType();
|
||||
// FIXME Some banks cannot handle OrderID element in download process. Add parameter in
|
||||
// configuration!!!
|
||||
orderDetails =
|
||||
EbicsXmlFactory.createStaticHeaderOrderDetailsType(
|
||||
ebicsUser.getNextOrderId(), // session.getUser().getPartner().nextOrderId(),
|
||||
orderAttribute.getOrderAttributes(),
|
||||
orderType,
|
||||
standardOrderParamsType);
|
||||
}
|
||||
xstatic =
|
||||
EbicsXmlFactory.createStaticHeaderType(
|
||||
session.getBankID(),
|
||||
nonce,
|
||||
ebicsPartner.getPartnerId(),
|
||||
product,
|
||||
ebicsUser.getSecurityMedium(),
|
||||
ebicsUser.getUserId(),
|
||||
Calendar.getInstance(),
|
||||
orderDetails,
|
||||
bankPubKeyDigests);
|
||||
header = EbicsXmlFactory.createEbicsRequestHeader(true, mutable, xstatic);
|
||||
body = EbicsXmlFactory.createEbicsRequestBody();
|
||||
request = EbicsXmlFactory.createEbicsRequest(1, "H003", header, body);
|
||||
document = EbicsXmlFactory.createEbicsRequestDocument(request);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private Date startRange;
|
||||
private Date endRange;
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.apps.bankpayment.ebics.exception.ReturnCode;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>DInitializationResponseElement</code> is the response element for ebics downloads
|
||||
* initializations.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class DInitializationResponseElement extends InitializationResponseElement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>DInitializationResponseElement</code> object
|
||||
*
|
||||
* @param factory the content factory
|
||||
* @param orderType the order type
|
||||
* @param name the element name
|
||||
*/
|
||||
public DInitializationResponseElement(
|
||||
ContentFactory factory, OrderType orderType, String name, EbicsUser ebicsUser) {
|
||||
super(factory, orderType, name, ebicsUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
String bodyRetCode;
|
||||
|
||||
super.build();
|
||||
if (!returnCode.isOk()) {
|
||||
return;
|
||||
}
|
||||
bodyRetCode = response.getBody().getReturnCode().getStringValue();
|
||||
returnCode = ReturnCode.toReturnCode(bodyRetCode, "");
|
||||
numSegments = (int) response.getHeader().getStatic().getNumSegments();
|
||||
if (numSegments > 0) {
|
||||
segmentNumber = (int) response.getHeader().getMutable().getSegmentNumber().getLongValue();
|
||||
lastSegment = response.getHeader().getMutable().getSegmentNumber().getLastSegment();
|
||||
transactionKey =
|
||||
response.getBody().getDataTransfer().getDataEncryptionInfo().getTransactionKey();
|
||||
orderData = response.getBody().getDataTransfer().getOrderData().getByteArrayValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total segments number.
|
||||
*
|
||||
* @return the total segments number.
|
||||
*/
|
||||
public int getSegmentsNumber() {
|
||||
return numSegments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns The current segment number.
|
||||
*
|
||||
* @return the segment number.
|
||||
*/
|
||||
public int getSegmentNumber() {
|
||||
return segmentNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if it is the last segment.
|
||||
*
|
||||
* @return True is it is the last segment.
|
||||
*/
|
||||
public boolean isLastSegment() {
|
||||
return lastSegment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction key.
|
||||
*
|
||||
* @return the transaction key.
|
||||
*/
|
||||
public byte[] getTransactionKey() {
|
||||
return transactionKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the order data.
|
||||
*
|
||||
* @return the order data.
|
||||
*/
|
||||
public byte[] getOrderData() {
|
||||
return orderData;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private int numSegments;
|
||||
private int segmentNumber;
|
||||
private boolean lastSegment;
|
||||
private byte[] transactionKey;
|
||||
private byte[] orderData;
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Body;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Header;
|
||||
import com.axelor.apps.account.ebics.schema.h003.MutableHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.MutableHeaderType.SegmentNumber;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>DTransferRequestElement</code> is the common elements for all ebics downloads.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class DTransferRequestElement extends TransferRequestElement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>DTransferRequestElement</code> element.
|
||||
*
|
||||
* @param session the current ebics session
|
||||
* @param type the order type
|
||||
* @param segmentNumber the segment number
|
||||
* @param lastSegment is it the last segment?
|
||||
* @param transactionId the transaction ID
|
||||
*/
|
||||
public DTransferRequestElement(
|
||||
EbicsSession session,
|
||||
OrderType type,
|
||||
int segmentNumber,
|
||||
boolean lastSegment,
|
||||
byte[] transactionId) {
|
||||
super(session, generateName(type), type, segmentNumber, lastSegment, transactionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildTransfer() throws AxelorException {
|
||||
EbicsRequest request;
|
||||
Header header;
|
||||
Body body;
|
||||
MutableHeaderType mutable;
|
||||
SegmentNumber segmentNumber;
|
||||
StaticHeaderType xstatic;
|
||||
|
||||
segmentNumber = EbicsXmlFactory.createSegmentNumber(this.segmentNumber, lastSegment);
|
||||
mutable = EbicsXmlFactory.createMutableHeaderType("Transfer", segmentNumber);
|
||||
xstatic = EbicsXmlFactory.createStaticHeaderType(session.getBankID(), transactionId);
|
||||
header = EbicsXmlFactory.createEbicsRequestHeader(true, mutable, xstatic);
|
||||
body = EbicsXmlFactory.createEbicsRequestBody();
|
||||
request = EbicsXmlFactory.createEbicsRequest(1, "H003", header, body);
|
||||
document = EbicsXmlFactory.createEbicsRequestDocument(request);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
}
|
||||
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>DTransferResponseElement</code> is the response element for all ebics downloads
|
||||
* transfers.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class DTransferResponseElement extends TransferResponseElement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>DTransferResponseElement</code> object.
|
||||
*
|
||||
* @param factory the content factory
|
||||
* @param orderType the order type
|
||||
* @param name the element name.
|
||||
*/
|
||||
public DTransferResponseElement(
|
||||
ContentFactory factory, OrderType orderType, String name, EbicsUser ebicsUser) {
|
||||
super(factory, name, ebicsUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
super.build();
|
||||
|
||||
orderData = response.getBody().getDataTransfer().getOrderData().getByteArrayValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the order data.
|
||||
*
|
||||
* @return the order data.
|
||||
*/
|
||||
public byte[] getOrderData() {
|
||||
return orderData;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private byte[] orderData;
|
||||
}
|
||||
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsRootElement;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import javax.xml.namespace.QName;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.apache.xmlbeans.XmlError;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
import org.apache.xmlbeans.XmlOptions;
|
||||
import org.jdom.Document;
|
||||
import org.jdom.JDOMException;
|
||||
import org.jdom.input.SAXBuilder;
|
||||
import org.jdom.output.Format;
|
||||
import org.jdom.output.XMLOutputter;
|
||||
|
||||
public abstract class DefaultEbicsRootElement implements EbicsRootElement {
|
||||
|
||||
/**
|
||||
* Constructs a new default <code>EbicsRootElement</code>
|
||||
*
|
||||
* @param session the current ebics session
|
||||
*/
|
||||
public DefaultEbicsRootElement(EbicsSession session) {
|
||||
this.session = session;
|
||||
suggestedPrefixes = new HashMap<String, String>();
|
||||
}
|
||||
|
||||
/** Constructs a new default <code>EbicsRootElement</code> */
|
||||
public DefaultEbicsRootElement() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the Suggested Prefixes when the XML is printed
|
||||
*
|
||||
* @param uri the namespace URI
|
||||
* @param prefix the namespace URI prefix
|
||||
*/
|
||||
protected static void setSaveSuggestedPrefixes(String uri, String prefix) {
|
||||
suggestedPrefixes.put(uri, prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a pretty XML document using jdom framework.
|
||||
*
|
||||
* @param input the XML input
|
||||
* @return the pretty XML document.
|
||||
* @throws JDOMException
|
||||
* @throws EbicsException pretty print fails
|
||||
*/
|
||||
public byte[] prettyPrint() throws AxelorException {
|
||||
Document document;
|
||||
XMLOutputter xmlOutputter;
|
||||
SAXBuilder sxb;
|
||||
ByteArrayOutputStream output;
|
||||
|
||||
sxb = new SAXBuilder();
|
||||
output = new ByteArrayOutputStream();
|
||||
xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
|
||||
|
||||
try {
|
||||
document = sxb.build(new InputStreamReader(new ByteArrayInputStream(toByteArray()), "UTF-8"));
|
||||
xmlOutputter.output(document, output);
|
||||
} catch (IOException | JDOMException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
|
||||
return output.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a schema location to the current ebics root element.
|
||||
*
|
||||
* @param namespaceURI the name space URI
|
||||
* @param localPart the local part
|
||||
* @param prefix the prefix
|
||||
* @param value the value
|
||||
*/
|
||||
public void insertSchemaLocation(
|
||||
String namespaceURI, String localPart, String prefix, String value) {
|
||||
XmlCursor cursor;
|
||||
|
||||
cursor = document.newCursor();
|
||||
while (cursor.hasNextToken()) {
|
||||
if (cursor.isStart()) {
|
||||
cursor.toNextToken();
|
||||
cursor.insertAttributeWithValue(new QName(namespaceURI, localPart, prefix), value);
|
||||
break;
|
||||
} else {
|
||||
cursor.toNextToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random file name with a prefix.
|
||||
*
|
||||
* @param type the order type.
|
||||
* @return the generated file name.
|
||||
*/
|
||||
public static String generateName(OrderType type) {
|
||||
return type.getOrderType() + new BigInteger(130, new SecureRandom()).toString(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random file name with a prefix.
|
||||
*
|
||||
* @param type the prefix to use.
|
||||
* @return the generated file name.
|
||||
*/
|
||||
public static String generateName(String prefix) {
|
||||
return prefix + new BigInteger(130, new SecureRandom()).toString(32);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new String(toByteArray());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
XmlOptions options;
|
||||
|
||||
options = new XmlOptions();
|
||||
options.setSavePrettyPrint();
|
||||
options.setSaveSuggestedPrefixes(suggestedPrefixes);
|
||||
return document.xmlText(options).getBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNamespaceDecl(String prefix, String uri) {
|
||||
XmlCursor cursor;
|
||||
|
||||
cursor = document.newCursor();
|
||||
while (cursor.hasNextToken()) {
|
||||
if (cursor.isStart()) {
|
||||
cursor.toNextToken();
|
||||
cursor.insertNamespace(prefix, uri);
|
||||
break;
|
||||
} else {
|
||||
cursor.toNextToken();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws AxelorException {
|
||||
ArrayList<XmlError> validationMessages;
|
||||
boolean isValid;
|
||||
|
||||
validationMessages = new ArrayList<XmlError>();
|
||||
isValid = document.validate(new XmlOptions().setErrorListener(validationMessages));
|
||||
|
||||
if (!isValid) {
|
||||
String message;
|
||||
Iterator<XmlError> iter;
|
||||
|
||||
iter = validationMessages.iterator();
|
||||
message = "";
|
||||
while (iter.hasNext()) {
|
||||
if (!message.equals("")) {
|
||||
message += ";";
|
||||
}
|
||||
message += iter.next().getMessage();
|
||||
}
|
||||
|
||||
throw new AxelorException(TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, message);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(OutputStream out) throws AxelorException, JDOMException {
|
||||
try {
|
||||
byte[] element;
|
||||
|
||||
element = prettyPrint();
|
||||
out.write(element);
|
||||
out.flush();
|
||||
out.close();
|
||||
} catch (IOException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void print(PrintStream stream) {
|
||||
stream.println(document.toString());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
protected XmlObject document;
|
||||
protected EbicsSession session;
|
||||
private static Map<String, String> suggestedPrefixes;
|
||||
}
|
||||
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsRootElement;
|
||||
import com.axelor.apps.bankpayment.ebics.exception.ReturnCode;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsUserService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.io.IOException;
|
||||
import org.apache.xmlbeans.XmlException;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
|
||||
/**
|
||||
* The <code>DefaultResponseElement</code> is the common element for all ebics server responses.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public abstract class DefaultResponseElement extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Constructs a new ebics response element.
|
||||
*
|
||||
* @param factory the content factory containing the response.
|
||||
* @param name the element name
|
||||
*/
|
||||
public DefaultResponseElement(ContentFactory factory, String name, EbicsUser ebicsUser) {
|
||||
this.factory = factory;
|
||||
this.name = name;
|
||||
this.ebicsUser = ebicsUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the content of a <code>ContentFactory</code>
|
||||
*
|
||||
* @param factory the content factory
|
||||
* @throws EbicsException parse error
|
||||
*/
|
||||
protected void parse(ContentFactory factory) throws AxelorException {
|
||||
try {
|
||||
document = XmlObject.Factory.parse(factory.getContent());
|
||||
} catch (XmlException | IOException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reports the return code to the user.
|
||||
*
|
||||
* @throws EbicsException request fails.
|
||||
*/
|
||||
public void report(EbicsRootElement[] rootElements) throws AxelorException {
|
||||
|
||||
log(rootElements);
|
||||
|
||||
if (!returnCode.isOk()) {
|
||||
returnCode.throwException();
|
||||
}
|
||||
}
|
||||
|
||||
protected void log(EbicsRootElement[] rootElements) {
|
||||
if (ebicsUser != null && name != null && returnCode != null) {
|
||||
Beans.get(EbicsUserService.class)
|
||||
.logRequest(
|
||||
ebicsUser.getId(), name.substring(0, 3), returnCode.getSymbolicName(), rootElements);
|
||||
ebicsUser = null; // Prevent further log on same request
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name + ".xml";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private String name;
|
||||
private EbicsUser ebicsUser;
|
||||
protected ContentFactory factory;
|
||||
protected ReturnCode returnCode;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.apps.bankpayment.ebics.client.UnsecuredRequestElement;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import javax.xml.XMLConstants;
|
||||
|
||||
/**
|
||||
* The <code>HIARequestElement</code> is the root element used to send the authentication and
|
||||
* encryption keys to the ebics bank server
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class HIARequestElement extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Constructs a new HIA Request root element
|
||||
*
|
||||
* @param session the current ebics session
|
||||
* @param orderId the order id, if null a random one is generated.
|
||||
*/
|
||||
public HIARequestElement(EbicsSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "HIARequest.xml";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
HIARequestOrderDataElement requestOrderData;
|
||||
|
||||
requestOrderData = new HIARequestOrderDataElement(session);
|
||||
try {
|
||||
requestOrderData.build();
|
||||
|
||||
unsecuredRequest =
|
||||
new UnsecuredRequestElement(
|
||||
session, OrderType.HIA, EbicsUtils.zip(requestOrderData.prettyPrint()));
|
||||
unsecuredRequest.build();
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
setSaveSuggestedPrefixes("http://www.ebics.org/H003", XMLConstants.DEFAULT_NS_PREFIX);
|
||||
|
||||
return unsecuredRequest.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws AxelorException {
|
||||
unsecuredRequest.validate();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private UnsecuredRequestElement unsecuredRequest;
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.AuthenticationPubKeyInfoType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EncryptionPubKeyInfoType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.HIARequestOrderDataType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.PubKeyValueType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.RSAKeyValueType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.X509DataType;
|
||||
import com.axelor.apps.bankpayment.db.EbicsCertificate;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Calendar;
|
||||
import javax.xml.XMLConstants;
|
||||
|
||||
/**
|
||||
* The <code>HIARequestOrderDataElement</code> is the element that contains X002 and E002 keys
|
||||
* information needed for a HIA request in order to send the authentication and encryption user keys
|
||||
* to the bank server.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class HIARequestOrderDataElement extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Constructs a new HIA Request Order Data element
|
||||
*
|
||||
* @param session the current ebics session
|
||||
*/
|
||||
public HIARequestOrderDataElement(EbicsSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() {
|
||||
HIARequestOrderDataType request;
|
||||
AuthenticationPubKeyInfoType authenticationPubKeyInfo;
|
||||
EncryptionPubKeyInfoType encryptionPubKeyInfo;
|
||||
PubKeyValueType encryptionPubKeyValue;
|
||||
X509DataType encryptionX509Data = null;
|
||||
RSAKeyValueType encryptionRsaKeyValue;
|
||||
PubKeyValueType authPubKeyValue;
|
||||
X509DataType authX509Data = null;
|
||||
RSAKeyValueType authRsaKeyValue;
|
||||
|
||||
EbicsCertificate certificate = session.getUser().getE002Certificate();
|
||||
|
||||
encryptionX509Data =
|
||||
EbicsXmlFactory.createX509DataType(session.getUser().getDn(), certificate.getCertificate());
|
||||
|
||||
// Include Certificate issuer and serial ?
|
||||
// encryptionX509Data = EbicsXmlFactory.createX509DataType(session.getUser().getDn(),
|
||||
// certificate.getCertificate(), certificate.getIssuer(), new
|
||||
// BigInteger(certificate.getSerial(), 16));
|
||||
|
||||
encryptionRsaKeyValue =
|
||||
EbicsXmlFactory.createRSAKeyValueType(
|
||||
new BigInteger(certificate.getPublicKeyExponent(), 16).toByteArray(),
|
||||
new BigInteger(certificate.getPublicKeyModulus(), 16).toByteArray());
|
||||
|
||||
encryptionPubKeyValue =
|
||||
EbicsXmlFactory.createH003PubKeyValueType(encryptionRsaKeyValue, Calendar.getInstance());
|
||||
encryptionPubKeyInfo =
|
||||
EbicsXmlFactory.createEncryptionPubKeyInfoType(
|
||||
"E002", encryptionPubKeyValue, encryptionX509Data);
|
||||
certificate = session.getUser().getX002Certificate();
|
||||
|
||||
authX509Data =
|
||||
EbicsXmlFactory.createX509DataType(session.getUser().getDn(), certificate.getCertificate());
|
||||
|
||||
// Include Certificate issuer and serial ?
|
||||
// authX509Data = EbicsXmlFactory.createX509DataType(session.getUser().getDn(),
|
||||
// certificate.getCertificate(), certificate.getIssuer(), new
|
||||
// BigInteger(certificate.getSerial(), 16));
|
||||
|
||||
authRsaKeyValue =
|
||||
EbicsXmlFactory.createRSAKeyValueType(
|
||||
new BigInteger(certificate.getPublicKeyExponent(), 16).toByteArray(),
|
||||
new BigInteger(certificate.getPublicKeyModulus(), 16).toByteArray());
|
||||
|
||||
authPubKeyValue =
|
||||
EbicsXmlFactory.createH003PubKeyValueType(authRsaKeyValue, Calendar.getInstance());
|
||||
authenticationPubKeyInfo =
|
||||
EbicsXmlFactory.createAuthenticationPubKeyInfoType("X002", authPubKeyValue, authX509Data);
|
||||
request =
|
||||
EbicsXmlFactory.createHIARequestOrderDataType(
|
||||
authenticationPubKeyInfo,
|
||||
encryptionPubKeyInfo,
|
||||
session.getUser().getEbicsPartner().getPartnerId(),
|
||||
session.getUser().getUserId());
|
||||
document = EbicsXmlFactory.createHIARequestOrderDataDocument(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "HIARequestOrderData.xml";
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
addNamespaceDecl("ds", "http://www.w3.org/2000/09/xmldsig#");
|
||||
setSaveSuggestedPrefixes("http://www.ebics.org/S001", XMLConstants.DEFAULT_NS_PREFIX);
|
||||
|
||||
return super.toByteArray();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>HPBRequestElement</code> is the element to be sent when a HPB request is needed to
|
||||
* retrieve the bank public keys
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class HPBRequestElement extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Constructs a new HPB Request element.
|
||||
*
|
||||
* @param session the current ebics session.
|
||||
*/
|
||||
public HPBRequestElement(EbicsSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "HPBRequest.xml";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
SignedInfo signedInfo;
|
||||
byte[] signature;
|
||||
|
||||
noPubKeyDigestsRequest = new NoPubKeyDigestsRequestElement(session);
|
||||
noPubKeyDigestsRequest.build();
|
||||
signedInfo = new SignedInfo(session.getUser(), noPubKeyDigestsRequest.getDigest());
|
||||
signedInfo.build();
|
||||
noPubKeyDigestsRequest.setAuthSignature(signedInfo.getSignatureType());
|
||||
signature = signedInfo.sign(noPubKeyDigestsRequest.toByteArray());
|
||||
noPubKeyDigestsRequest.setSignatureValue(signature);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
return noPubKeyDigestsRequest.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws AxelorException {
|
||||
noPubKeyDigestsRequest.validate();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private NoPubKeyDigestsRequestElement noPubKeyDigestsRequest;
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.HPBResponseOrderDataDocument;
|
||||
import com.axelor.apps.account.ebics.schema.h003.HPBResponseOrderDataType;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>HPBResponseOrderDataElement</code> contains the public bank keys in encrypted mode. The
|
||||
* user should decrypt with his encryption key to have the bank public keys.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class HPBResponseOrderDataElement extends DefaultResponseElement {
|
||||
|
||||
/**
|
||||
* Creates a new <code>HPBResponseOrderDataElement</code> from a given content factory.
|
||||
*
|
||||
* @param factory the content factory.
|
||||
*/
|
||||
public HPBResponseOrderDataElement(ContentFactory factory, EbicsUser ebicsUser) {
|
||||
super(factory, "HPBData", ebicsUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authentication bank certificate.
|
||||
*
|
||||
* @return the authentication bank certificate.
|
||||
*/
|
||||
public byte[] getBankX002Certificate() {
|
||||
return response.getAuthenticationPubKeyInfo().getX509Data().getX509CertificateArray(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the encryption bank certificate.
|
||||
*
|
||||
* @return the encryption bank certificate.
|
||||
*/
|
||||
public byte[] getBankE002Certificate() {
|
||||
return response.getEncryptionPubKeyInfo().getX509Data().getX509CertificateArray(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
parse(factory);
|
||||
response = ((HPBResponseOrderDataDocument) document).getHPBResponseOrderData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "HPBData.xml";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private HPBResponseOrderDataType response;
|
||||
}
|
||||
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.apps.bankpayment.ebics.client.UnsecuredRequestElement;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import javax.xml.XMLConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The INI request XML element. This root element is to be sent to the ebics server to initiate the
|
||||
* signature certificate.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class INIRequestElement extends DefaultEbicsRootElement {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
/**
|
||||
* Constructs a new INI request element.
|
||||
*
|
||||
* @param session the ebics session.
|
||||
* @param orderId the order id, if null a random one is generated.
|
||||
*/
|
||||
public INIRequestElement(EbicsSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "INIRequest.xml";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
SignaturePubKeyOrderDataElement signaturePubKey;
|
||||
|
||||
signaturePubKey = new SignaturePubKeyOrderDataElement(session);
|
||||
log.debug("SignaturePubKeyOrderDataElement OK");
|
||||
signaturePubKey.build();
|
||||
log.debug("signaturePubKey.build OK");
|
||||
unsecuredRequest =
|
||||
new UnsecuredRequestElement(
|
||||
session, OrderType.INI, EbicsUtils.zip(signaturePubKey.prettyPrint()));
|
||||
|
||||
log.debug("UnsecuredRequestElement OK");
|
||||
unsecuredRequest.build();
|
||||
log.debug("unsecuredRequest.build OK");
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
setSaveSuggestedPrefixes("http://www.ebics.org/H003", XMLConstants.DEFAULT_NS_PREFIX);
|
||||
|
||||
return unsecuredRequest.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() throws AxelorException {
|
||||
unsecuredRequest.validate();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private UnsecuredRequestElement unsecuredRequest;
|
||||
}
|
||||
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.SignatureType;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.xml.XMLConstants;
|
||||
import org.apache.commons.codec.DecoderException;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
|
||||
/**
|
||||
* The <code>InitializationRequestElement</code> is the root element for ebics uploads and downloads
|
||||
* requests. The response of this element is then used either to upload or download files from the
|
||||
* ebics server.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public abstract class InitializationRequestElement extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Construct a new <code>InitializationRequestElement</code> root element.
|
||||
*
|
||||
* @param session the current ebics session.
|
||||
* @param type the initialization type (UPLOAD, DOWNLOAD).
|
||||
* @param name the element name.
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public InitializationRequestElement(EbicsSession session, OrderType type, String name)
|
||||
throws AxelorException {
|
||||
super(session);
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
nonce = EbicsUtils.generateNonce();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
SignedInfo signedInfo;
|
||||
|
||||
buildInitialization();
|
||||
signedInfo = new SignedInfo(session.getUser(), getDigest());
|
||||
signedInfo.build();
|
||||
((EbicsRequestDocument) document)
|
||||
.getEbicsRequest()
|
||||
.setAuthSignature((SignatureType) signedInfo.getSignatureType());
|
||||
((EbicsRequestDocument) document)
|
||||
.getEbicsRequest()
|
||||
.getAuthSignature()
|
||||
.setSignatureValue(
|
||||
EbicsXmlFactory.createSignatureValueType(signedInfo.sign(toByteArray())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name + ".xml";
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
setSaveSuggestedPrefixes("http://www.ebics.org/H003", XMLConstants.DEFAULT_NS_PREFIX);
|
||||
|
||||
return super.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the digest value of the authenticated XML portions.
|
||||
*
|
||||
* @return the digest value.
|
||||
* @throws EbicsException Failed to retrieve the digest value.
|
||||
*/
|
||||
public byte[] getDigest() throws AxelorException {
|
||||
addNamespaceDecl("ds", "http://www.w3.org/2000/09/xmldsig#");
|
||||
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256", "BC").digest(EbicsUtils.canonize(toByteArray()));
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
} catch (NoSuchProviderException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the element type.
|
||||
*
|
||||
* @return the element type.
|
||||
*/
|
||||
public String getType() {
|
||||
return type.getOrderType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes an hexadecimal input.
|
||||
*
|
||||
* @param hex the hexadecimal input
|
||||
* @return the decoded hexadecimal value
|
||||
* @throws EbicsException
|
||||
*/
|
||||
protected byte[] decodeHex(byte[] hex) throws AxelorException {
|
||||
if (hex == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
"Bank digest is empty, HPB request must be performed before");
|
||||
}
|
||||
|
||||
try {
|
||||
return Hex.decodeHex((new String(hex)).toCharArray());
|
||||
} catch (DecoderException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the upload transaction key
|
||||
*
|
||||
* @return the transaction key
|
||||
*/
|
||||
protected byte[] generateTransactionKey() throws AxelorException {
|
||||
try {
|
||||
Cipher cipher;
|
||||
|
||||
cipher = Cipher.getInstance("RSA/NONE/PKCS1Padding", BouncyCastleProvider.PROVIDER_NAME);
|
||||
cipher.init(Cipher.ENCRYPT_MODE, session.getBankE002Key());
|
||||
|
||||
return cipher.doFinal(nonce);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the initialization request according to the element type.
|
||||
*
|
||||
* @throws EbicsException build fails
|
||||
*/
|
||||
public abstract void buildInitialization() throws AxelorException;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private String name;
|
||||
protected OrderType type;
|
||||
protected byte[] nonce;
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsResponseDocument;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsResponseDocument.EbicsResponse;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.apps.bankpayment.ebics.exception.ReturnCode;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>InitializationResponseElement</code> is the common element for transfer initialization
|
||||
* responses.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class InitializationResponseElement extends DefaultResponseElement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>InitializationResponseElement</code> element.
|
||||
*
|
||||
* @param factory the content factory
|
||||
* @param orderType the order type
|
||||
* @param name the element name
|
||||
*/
|
||||
public InitializationResponseElement(
|
||||
ContentFactory factory, OrderType orderType, String name, EbicsUser ebicsUser) {
|
||||
super(factory, name, ebicsUser);
|
||||
this.orderType = orderType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
String code;
|
||||
String text;
|
||||
|
||||
parse(factory);
|
||||
response = ((EbicsResponseDocument) document).getEbicsResponse();
|
||||
code = response.getHeader().getMutable().getReturnCode();
|
||||
text = response.getHeader().getMutable().getReportText();
|
||||
returnCode = ReturnCode.toReturnCode(code, text);
|
||||
transactionId = response.getHeader().getStatic().getTransactionID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction ID.
|
||||
*
|
||||
* @return the transaction ID.
|
||||
*/
|
||||
public byte[] getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the order type.
|
||||
*
|
||||
* @return the order type.
|
||||
*/
|
||||
public String getOrderType() {
|
||||
return orderType.getOrderType();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
protected EbicsResponse response;
|
||||
private OrderType orderType;
|
||||
private byte[] transactionId;
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsKeyManagementResponseDocument;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsKeyManagementResponseDocument.EbicsKeyManagementResponse;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.exception.ReturnCode;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>KeyManagementResponseElement</code> is the common element for ebics key management
|
||||
* requests. This element aims to control the returned code from the ebics server and throw an
|
||||
* exception if it is not an EBICS_OK code.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class KeyManagementResponseElement extends DefaultResponseElement {
|
||||
|
||||
/**
|
||||
* Creates a new <code>KeyManagementResponseElement</code> from a given <code>ContentFactory
|
||||
* </code>
|
||||
*
|
||||
* @param factory the content factory enclosing the ebics response
|
||||
* @param name the element name
|
||||
*/
|
||||
public KeyManagementResponseElement(ContentFactory factory, String name, EbicsUser ebicsUser) {
|
||||
super(factory, name, ebicsUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transaction key of the response.
|
||||
*
|
||||
* @return the transaction key.
|
||||
*/
|
||||
public byte[] getTransactionKey() {
|
||||
return response.getBody().getDataTransfer().getDataEncryptionInfo().getTransactionKey();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the order data of the response.
|
||||
*
|
||||
* @return the order data.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public byte[] getOrderData() {
|
||||
return response.getBody().getDataTransfer().getOrderData().byteArrayValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
String code;
|
||||
String text;
|
||||
|
||||
parse(factory);
|
||||
response = ((EbicsKeyManagementResponseDocument) document).getEbicsKeyManagementResponse();
|
||||
code = response.getHeader().getMutable().getReturnCode();
|
||||
text = response.getHeader().getMutable().getReportText();
|
||||
returnCode = ReturnCode.toReturnCode(code, text);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private EbicsKeyManagementResponse response;
|
||||
}
|
||||
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsNoPubKeyDigestsRequestDocument;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsNoPubKeyDigestsRequestDocument.EbicsNoPubKeyDigestsRequest;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsNoPubKeyDigestsRequestDocument.EbicsNoPubKeyDigestsRequest.Body;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsNoPubKeyDigestsRequestDocument.EbicsNoPubKeyDigestsRequest.Header;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EmptyMutableHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.NoPubKeyDigestsRequestStaticHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.OrderDetailsType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.ProductElementType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.SignatureType;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderAttribute;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.util.Calendar;
|
||||
|
||||
/**
|
||||
* The <code>NoPubKeyDigestsRequestElement</code> is the root element for a HPB ebics server
|
||||
* request.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class NoPubKeyDigestsRequestElement extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Construct a new No Public Key Digests Request element.
|
||||
*
|
||||
* @param session the current ebics session.
|
||||
*/
|
||||
public NoPubKeyDigestsRequestElement(EbicsSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the digest value of the authenticated XML portions.
|
||||
*
|
||||
* @return the digest value.
|
||||
* @throws EbicsException Failed to retrieve the digest value.
|
||||
*/
|
||||
public byte[] getDigest() throws AxelorException {
|
||||
addNamespaceDecl("ds", "http://www.w3.org/2000/09/xmldsig#");
|
||||
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256", "BC").digest(EbicsUtils.canonize(toByteArray()));
|
||||
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
throw new AxelorException(e.getCause(), TraceBackRepository.TYPE_TECHNICAL, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the authentication signature of the <code>NoPubKeyDigestsRequestElement</code>
|
||||
*
|
||||
* @param authSignature the the authentication signature.
|
||||
*/
|
||||
public void setAuthSignature(SignatureType authSignature) {
|
||||
((EbicsNoPubKeyDigestsRequestDocument) document)
|
||||
.getEbicsNoPubKeyDigestsRequest()
|
||||
.setAuthSignature(authSignature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the signature value of the request.
|
||||
*
|
||||
* @param signature the signature value
|
||||
*/
|
||||
public void setSignatureValue(byte[] signature) {
|
||||
((EbicsNoPubKeyDigestsRequestDocument) document)
|
||||
.getEbicsNoPubKeyDigestsRequest()
|
||||
.getAuthSignature()
|
||||
.setSignatureValue(EbicsXmlFactory.createSignatureValueType(signature));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
EbicsNoPubKeyDigestsRequest request;
|
||||
Body body;
|
||||
Header header;
|
||||
EmptyMutableHeaderType mutable;
|
||||
NoPubKeyDigestsRequestStaticHeaderType xstatic;
|
||||
ProductElementType product;
|
||||
OrderDetailsType orderDetails;
|
||||
|
||||
EbicsUser ebicsUser = session.getUser();
|
||||
EbicsPartner ebicsPartner = ebicsUser.getEbicsPartner();
|
||||
|
||||
OrderAttribute orderAttribute =
|
||||
new OrderAttribute(OrderType.HPB, ebicsPartner.getEbicsTypeSelect());
|
||||
orderAttribute.build();
|
||||
|
||||
product =
|
||||
EbicsXmlFactory.creatProductElementType(
|
||||
session.getProduct().getLanguage(), session.getProduct().getName());
|
||||
orderDetails =
|
||||
EbicsXmlFactory.createOrderDetailsType(
|
||||
orderAttribute.getOrderAttributes(), null, OrderType.HPB.getOrderType());
|
||||
xstatic =
|
||||
EbicsXmlFactory.createNoPubKeyDigestsRequestStaticHeaderType(
|
||||
session.getBankID(),
|
||||
EbicsUtils.generateNonce(),
|
||||
Calendar.getInstance(),
|
||||
ebicsPartner.getPartnerId(),
|
||||
ebicsUser.getUserId(),
|
||||
product,
|
||||
orderDetails,
|
||||
ebicsUser.getSecurityMedium());
|
||||
mutable = EbicsXmlFactory.createEmptyMutableHeaderType();
|
||||
header = EbicsXmlFactory.createDigestsRequestHeader(true, mutable, xstatic);
|
||||
body = EbicsXmlFactory.createDigestsRequestBody();
|
||||
request = EbicsXmlFactory.createEbicsNoPubKeyDigestsRequest(1, "H003", header, body);
|
||||
document = EbicsXmlFactory.createEbicsNoPubKeyDigestsRequestDocument(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
// setSaveSuggestedPrefixes("http://www.w3.org/2000/09/xmldsig#", "ds"); //TODO TO CHECK
|
||||
|
||||
setSaveSuggestedPrefixes("http://www.w3.org/2000/09/xmldsig#", "ds");
|
||||
setSaveSuggestedPrefixes("http://www.ebics.org/H003", "");
|
||||
|
||||
//
|
||||
// addNamespaceDecl("ds", "http://www.w3.org/2000/09/xmldsig#");
|
||||
//
|
||||
// setSaveSuggestedPrefixes("http://www.ebics.org/H003", XMLConstants.DEFAULT_NS_PREFIX);
|
||||
|
||||
return super.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "NoPubKeyDigestsRequest.xml";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
}
|
||||
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Body;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Body.TransferReceipt;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Header;
|
||||
import com.axelor.apps.account.ebics.schema.h003.MutableHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import javax.xml.XMLConstants;
|
||||
|
||||
/**
|
||||
* The <code>ReceiptRequestElement</code> is the element containing the receipt request to tell the
|
||||
* server bank that all segments are received.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class ReceiptRequestElement extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Construct a new <code>ReceiptRequestElement</code> element.
|
||||
*
|
||||
* @param session the current ebics session
|
||||
* @param name the element name
|
||||
*/
|
||||
public ReceiptRequestElement(EbicsSession session, byte[] transactionId, String name) {
|
||||
super(session);
|
||||
this.transactionId = transactionId;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
EbicsRequest request;
|
||||
Header header;
|
||||
Body body;
|
||||
MutableHeaderType mutable;
|
||||
StaticHeaderType xstatic;
|
||||
TransferReceipt transferReceipt;
|
||||
SignedInfo signedInfo;
|
||||
|
||||
mutable = EbicsXmlFactory.createMutableHeaderType("Receipt", null);
|
||||
xstatic = EbicsXmlFactory.createStaticHeaderType(session.getBankID(), transactionId);
|
||||
header = EbicsXmlFactory.createEbicsRequestHeader(true, mutable, xstatic);
|
||||
transferReceipt = EbicsXmlFactory.createTransferReceipt(true, 0);
|
||||
body = EbicsXmlFactory.createEbicsRequestBody(transferReceipt);
|
||||
request = EbicsXmlFactory.createEbicsRequest(1, "H003", header, body);
|
||||
document = EbicsXmlFactory.createEbicsRequestDocument(request);
|
||||
signedInfo = new SignedInfo(session.getUser(), getDigest());
|
||||
signedInfo.build();
|
||||
((EbicsRequestDocument) document)
|
||||
.getEbicsRequest()
|
||||
.setAuthSignature(signedInfo.getSignatureType());
|
||||
((EbicsRequestDocument) document)
|
||||
.getEbicsRequest()
|
||||
.getAuthSignature()
|
||||
.setSignatureValue(
|
||||
EbicsXmlFactory.createSignatureValueType(signedInfo.sign(toByteArray())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
setSaveSuggestedPrefixes("http://www.ebics.org/H003", XMLConstants.DEFAULT_NS_PREFIX);
|
||||
|
||||
return super.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name + ".xml";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the digest value of the authenticated XML portions.
|
||||
*
|
||||
* @return the digest value.
|
||||
* @throws EbicsException Failed to retrieve the digest value.
|
||||
*/
|
||||
public byte[] getDigest() throws AxelorException {
|
||||
addNamespaceDecl("ds", "http://www.w3.org/2000/09/xmldsig#");
|
||||
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256", "BC").digest(EbicsUtils.canonize(toByteArray()));
|
||||
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private byte[] transactionId;
|
||||
private String name;
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsResponseDocument;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsResponseDocument.EbicsResponse;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsRootElement;
|
||||
import com.axelor.apps.bankpayment.ebics.exception.ReturnCode;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>ReceiptResponseElement</code> is the response element for ebics receipt request.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class ReceiptResponseElement extends DefaultResponseElement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>ReceiptResponseElement</code> object
|
||||
*
|
||||
* @param factory the content factory
|
||||
* @param name the element name
|
||||
*/
|
||||
public ReceiptResponseElement(ContentFactory factory, String name, EbicsUser ebicsUser) {
|
||||
super(factory, name, ebicsUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
String code;
|
||||
String text;
|
||||
EbicsResponse response;
|
||||
|
||||
parse(factory);
|
||||
response = ((EbicsResponseDocument) document).getEbicsResponse();
|
||||
code = response.getHeader().getMutable().getReturnCode();
|
||||
text = response.getHeader().getMutable().getReportText();
|
||||
returnCode = ReturnCode.toReturnCode(code, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void report(EbicsRootElement[] rootElements) throws AxelorException {
|
||||
|
||||
log(rootElements);
|
||||
|
||||
if (!returnCode.equals(ReturnCode.EBICS_DOWNLOAD_POSTPROCESS_DONE)) {
|
||||
returnCode.throwException();
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.DataEncryptionInfoType.EncryptionPubKeyDigest;
|
||||
import com.axelor.apps.account.ebics.schema.h003.DataTransferRequestType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.DataTransferRequestType.DataEncryptionInfo;
|
||||
import com.axelor.apps.account.ebics.schema.h003.DataTransferRequestType.SignatureData;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Body;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Header;
|
||||
import com.axelor.apps.account.ebics.schema.h003.MutableHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StandardOrderParamsType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderOrderDetailsType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderOrderDetailsType.OrderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.BankPubKeyDigests;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.BankPubKeyDigests.Authentication;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.BankPubKeyDigests.Encryption;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.Product;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.certificate.KeyUtil;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderAttribute;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.util.Calendar;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* The <code>SPRRequestElement</code> is the request element for revoking a subscriber
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class SPRRequestElement extends InitializationRequestElement {
|
||||
|
||||
/**
|
||||
* Constructs a new SPR request element.
|
||||
*
|
||||
* @param session the current ebic session.
|
||||
*/
|
||||
public SPRRequestElement(EbicsSession session) throws AxelorException {
|
||||
super(session, com.axelor.apps.bankpayment.ebics.client.OrderType.SPR, "SPRRequest.xml");
|
||||
keySpec = new SecretKeySpec(nonce, "EAS");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildInitialization() throws AxelorException {
|
||||
EbicsRequest request;
|
||||
Header header;
|
||||
Body body;
|
||||
MutableHeaderType mutable;
|
||||
StaticHeaderType xstatic;
|
||||
Product product;
|
||||
BankPubKeyDigests bankPubKeyDigests;
|
||||
Authentication authentication;
|
||||
Encryption encryption;
|
||||
DataTransferRequestType dataTransfer;
|
||||
DataEncryptionInfo dataEncryptionInfo;
|
||||
SignatureData signatureData;
|
||||
EncryptionPubKeyDigest encryptionPubKeyDigest;
|
||||
StaticHeaderOrderDetailsType orderDetails;
|
||||
OrderType orderType;
|
||||
StandardOrderParamsType standardOrderParamsType;
|
||||
UserSignature userSignature;
|
||||
|
||||
EbicsUser ebicsUser = session.getUser();
|
||||
EbicsPartner ebicsPartner = ebicsUser.getEbicsPartner();
|
||||
|
||||
userSignature =
|
||||
new UserSignature(ebicsUser, generateName("SIG"), "A005", " ".getBytes(), " ".getBytes());
|
||||
// TODO Manage the ebics ts case, with an eletronic signature of the user
|
||||
userSignature.build();
|
||||
userSignature.validate();
|
||||
|
||||
mutable = EbicsXmlFactory.createMutableHeaderType("Initialisation", null);
|
||||
product =
|
||||
EbicsXmlFactory.createProduct(
|
||||
session.getProduct().getLanguage(), session.getProduct().getName());
|
||||
authentication =
|
||||
EbicsXmlFactory.createAuthentication(
|
||||
"X002",
|
||||
"http://www.w3.org/2001/04/xmlenc#sha256",
|
||||
decodeHex(KeyUtil.getKeyDigest(session.getBankX002Key())));
|
||||
encryption =
|
||||
EbicsXmlFactory.createEncryption(
|
||||
"E002",
|
||||
"http://www.w3.org/2001/04/xmlenc#sha256",
|
||||
decodeHex(KeyUtil.getKeyDigest(session.getBankE002Key())));
|
||||
bankPubKeyDigests = EbicsXmlFactory.createBankPubKeyDigests(authentication, encryption);
|
||||
orderType = EbicsXmlFactory.createOrderType(type.getOrderType());
|
||||
standardOrderParamsType = EbicsXmlFactory.createStandardOrderParamsType();
|
||||
|
||||
OrderAttribute orderAttribute = new OrderAttribute(type, ebicsPartner.getEbicsTypeSelect());
|
||||
orderAttribute.build();
|
||||
|
||||
orderDetails =
|
||||
EbicsXmlFactory.createStaticHeaderOrderDetailsType(
|
||||
ebicsUser.getNextOrderId(),
|
||||
orderAttribute.getOrderAttributes(),
|
||||
orderType,
|
||||
standardOrderParamsType);
|
||||
xstatic =
|
||||
EbicsXmlFactory.createStaticHeaderType(
|
||||
session.getBankID(),
|
||||
nonce,
|
||||
0,
|
||||
ebicsPartner.getPartnerId(),
|
||||
product,
|
||||
ebicsUser.getSecurityMedium(),
|
||||
ebicsUser.getUserId(),
|
||||
Calendar.getInstance(),
|
||||
orderDetails,
|
||||
bankPubKeyDigests);
|
||||
header = EbicsXmlFactory.createEbicsRequestHeader(true, mutable, xstatic);
|
||||
encryptionPubKeyDigest =
|
||||
EbicsXmlFactory.createEncryptionPubKeyDigest(
|
||||
"E002",
|
||||
"http://www.w3.org/2001/04/xmlenc#sha256",
|
||||
decodeHex(KeyUtil.getKeyDigest(session.getBankX002Key())));
|
||||
signatureData =
|
||||
EbicsXmlFactory.createSignatureData(
|
||||
true, EbicsUtils.encrypt(EbicsUtils.zip(userSignature.prettyPrint()), keySpec));
|
||||
|
||||
dataEncryptionInfo =
|
||||
EbicsXmlFactory.createDataEncryptionInfo(
|
||||
true, encryptionPubKeyDigest, generateTransactionKey());
|
||||
dataTransfer = EbicsXmlFactory.createDataTransferRequestType(dataEncryptionInfo, signatureData);
|
||||
body = EbicsXmlFactory.createEbicsRequestBody(dataTransfer);
|
||||
request = EbicsXmlFactory.createEbicsRequest(1, "H003", header, body);
|
||||
document = EbicsXmlFactory.createEbicsRequestDocument(request);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private SecretKeySpec keySpec;
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsResponseDocument;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsResponseDocument.EbicsResponse;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.exception.ReturnCode;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>SPRResponseElement</code> is the response element for an ebics subscriber revoking.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class SPRResponseElement extends DefaultResponseElement {
|
||||
|
||||
/**
|
||||
* Constructs a new SPR response element.
|
||||
*
|
||||
* @param factory the content factory
|
||||
*/
|
||||
public SPRResponseElement(ContentFactory factory, EbicsUser ebicsUser) {
|
||||
super(factory, "SPRResponse.xml", ebicsUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
String code;
|
||||
String text;
|
||||
|
||||
parse(factory);
|
||||
response = ((EbicsResponseDocument) document).getEbicsResponse();
|
||||
code = response.getHeader().getMutable().getReturnCode();
|
||||
text = response.getHeader().getMutable().getReportText();
|
||||
returnCode = ReturnCode.toReturnCode(code, text);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private EbicsResponse response;
|
||||
}
|
||||
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.s001.PubKeyValueType;
|
||||
import com.axelor.apps.account.ebics.schema.s001.SignaturePubKeyInfoType;
|
||||
import com.axelor.apps.account.ebics.schema.s001.SignaturePubKeyOrderDataType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.RSAKeyValueType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.X509DataType;
|
||||
import com.axelor.apps.bankpayment.db.EbicsCertificate;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Calendar;
|
||||
import javax.xml.XMLConstants;
|
||||
|
||||
/**
|
||||
* The <code>SignaturePubKeyOrderDataElement</code> is the order data component for the INI request.
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class SignaturePubKeyOrderDataElement extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Creates a new Signature Public Key Order Data element.
|
||||
*
|
||||
* @param session the current ebics session
|
||||
*/
|
||||
public SignaturePubKeyOrderDataElement(EbicsSession session) {
|
||||
super(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
SignaturePubKeyInfoType signaturePubKeyInfo;
|
||||
X509DataType x509Data;
|
||||
RSAKeyValueType rsaKeyValue;
|
||||
PubKeyValueType pubKeyValue;
|
||||
SignaturePubKeyOrderDataType signaturePubKeyOrderData;
|
||||
|
||||
EbicsCertificate certificate = session.getUser().getA005Certificate();
|
||||
|
||||
System.out.println("Certificate : " + new String(certificate.getCertificate()));
|
||||
System.out.println("Certificate size : " + certificate.getCertificate().length);
|
||||
|
||||
EbicsCertificate ebicsEertificate = session.getUser().getA005Certificate();
|
||||
|
||||
// Include certificate issuer and serial (certificate informations)
|
||||
// x509Data = EbicsXmlFactory.createX509DataType(ebicsEertificate.getSubject(), certEncoded,
|
||||
// ebicsEertificate.getIssuer(), new BigInteger(ebicsEertificate.getSerial(), 16));
|
||||
|
||||
x509Data =
|
||||
EbicsXmlFactory.createX509DataType(
|
||||
ebicsEertificate.getSubject(), ebicsEertificate.getCertificate());
|
||||
rsaKeyValue =
|
||||
EbicsXmlFactory.createRSAKeyValueType(
|
||||
new BigInteger(ebicsEertificate.getPublicKeyExponent(), 16).toByteArray(),
|
||||
new BigInteger(ebicsEertificate.getPublicKeyModulus(), 16).toByteArray());
|
||||
|
||||
pubKeyValue = EbicsXmlFactory.createPubKeyValueType(rsaKeyValue, Calendar.getInstance());
|
||||
signaturePubKeyInfo =
|
||||
EbicsXmlFactory.createSignaturePubKeyInfoType(x509Data, pubKeyValue, "A005");
|
||||
|
||||
signaturePubKeyOrderData =
|
||||
EbicsXmlFactory.createSignaturePubKeyOrderData(
|
||||
signaturePubKeyInfo,
|
||||
session.getUser().getEbicsPartner().getPartnerId(),
|
||||
session.getUser().getUserId());
|
||||
document = EbicsXmlFactory.createSignaturePubKeyOrderDataDocument(signaturePubKeyOrderData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "SignaturePubKeyOrderData.xml";
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
addNamespaceDecl("ds", "http://www.w3.org/2000/09/xmldsig#");
|
||||
setSaveSuggestedPrefixes("http://www.ebics.org/S001", XMLConstants.DEFAULT_NS_PREFIX);
|
||||
|
||||
return super.toByteArray();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.CanonicalizationMethodType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.DigestMethodType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.ReferenceType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.SignatureMethodType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.SignatureType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.SignedInfoType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.TransformType;
|
||||
import com.axelor.apps.account.ebics.schema.xmldsig.TransformsType;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsUserService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import javax.xml.XMLConstants;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import org.apache.xml.security.c14n.Canonicalizer;
|
||||
import org.apache.xml.security.transforms.TransformationException;
|
||||
import org.apache.xml.security.utils.IgnoreAllErrorHandler;
|
||||
import org.apache.xpath.XPathAPI;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
|
||||
/**
|
||||
* A representation of the SignedInfo element performing signature for signed ebics requests
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class SignedInfo extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>SignedInfo</code> element
|
||||
*
|
||||
* @param digest the digest value
|
||||
*/
|
||||
public SignedInfo(EbicsUser user, byte[] digest) {
|
||||
this.user = user;
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
CanonicalizationMethodType canonicalizationMethod;
|
||||
SignatureMethodType signatureMethod;
|
||||
ReferenceType reference;
|
||||
TransformsType transforms;
|
||||
DigestMethodType digestMethod;
|
||||
TransformType transform;
|
||||
SignedInfoType signedInfo;
|
||||
|
||||
if (digest == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get("digest value cannot be null"));
|
||||
}
|
||||
|
||||
transform = EbicsXmlFactory.createTransformType(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
|
||||
digestMethod =
|
||||
EbicsXmlFactory.createDigestMethodType("http://www.w3.org/2001/04/xmlenc#sha256");
|
||||
transforms = EbicsXmlFactory.createTransformsType(new TransformType[] {transform});
|
||||
reference =
|
||||
EbicsXmlFactory.createReferenceType(
|
||||
"#xpointer(//*[@authenticate='true'])", transforms, digestMethod, digest);
|
||||
signatureMethod =
|
||||
EbicsXmlFactory.createSignatureMethodType(
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
|
||||
canonicalizationMethod =
|
||||
EbicsXmlFactory.createCanonicalizationMethodType(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
|
||||
signedInfo =
|
||||
EbicsXmlFactory.createSignedInfoType(
|
||||
canonicalizationMethod, signatureMethod, new ReferenceType[] {reference});
|
||||
|
||||
document = EbicsXmlFactory.createSignatureType(signedInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the digest value.
|
||||
*
|
||||
* @return the digest value.
|
||||
*/
|
||||
public byte[] getDigest() {
|
||||
return digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the signed info element as an <code>XmlObject</code>
|
||||
*
|
||||
* @return he signed info element
|
||||
* @throws EbicsException user Signature and Canonicalization errors
|
||||
*/
|
||||
public SignatureType getSignatureType() {
|
||||
return ((SignatureType) document);
|
||||
}
|
||||
|
||||
/**
|
||||
* Canonizes and signs a given input with the authentication private key. of the EBICS user.
|
||||
*
|
||||
* <p>The given input to be signed is first Canonized using the
|
||||
* http://www.w3.org/TR/2001/REC-xml-c14n-20010315 algorithm.
|
||||
*
|
||||
* <p>The element to be canonized is only the SignedInfo element that should be contained in the
|
||||
* request to be signed. Otherwise, a {@link TransformationException} is thrown.
|
||||
*
|
||||
* <p>The namespace of the SignedInfo element should be named <b>ds</b> as specified in the EBICS
|
||||
* specification for common namespaces nomination.
|
||||
*
|
||||
* <p>The signature is ensured using the user X002 private key. This step is done in {@link
|
||||
* EbicsUser#authenticate(byte[]) authenticate}.
|
||||
*
|
||||
* @param toSign the input to sign
|
||||
* @return the signed input
|
||||
* @throws EbicsException signature fails.
|
||||
*/
|
||||
public byte[] sign(byte[] toSign) throws AxelorException {
|
||||
try {
|
||||
DocumentBuilderFactory factory;
|
||||
DocumentBuilder builder;
|
||||
Document document;
|
||||
Node node;
|
||||
Canonicalizer canonicalizer;
|
||||
|
||||
factory = DocumentBuilderFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
factory.setValidating(true);
|
||||
builder = factory.newDocumentBuilder();
|
||||
builder.setErrorHandler(new IgnoreAllErrorHandler());
|
||||
document = builder.parse(new ByteArrayInputStream(toSign));
|
||||
node = XPathAPI.selectSingleNode(document, "//ds:SignedInfo");
|
||||
canonicalizer = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_OMIT_COMMENTS);
|
||||
return Beans.get(EbicsUserService.class)
|
||||
.authenticate(user, canonicalizer.canonicalizeSubtree(node));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new AxelorException(e, TraceBackRepository.CATEGORY_CONFIGURATION_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
addNamespaceDecl(XMLConstants.DEFAULT_NS_PREFIX, "http://www.ebics.org/H003");
|
||||
setSaveSuggestedPrefixes("http://www.w3.org/2000/09/xmldsig#", "ds");
|
||||
|
||||
return super.toByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "SignedInfo.xml";
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private byte[] digest;
|
||||
private EbicsUser user;
|
||||
}
|
||||
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import javax.xml.XMLConstants;
|
||||
|
||||
/**
|
||||
* The <code>TransferRequestElement</code> is the common root element for all ebics transfer for the
|
||||
* bank server.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public abstract class TransferRequestElement extends DefaultEbicsRootElement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>TransferRequestElement</code> element.
|
||||
*
|
||||
* @param session the current ebics session
|
||||
* @param name the element name
|
||||
* @param type the order type
|
||||
* @param segmentNumber the segment number to be sent
|
||||
* @param lastSegment is it the last segment?
|
||||
* @param transactionID the transaction ID
|
||||
*/
|
||||
public TransferRequestElement(
|
||||
EbicsSession session,
|
||||
String name,
|
||||
OrderType type,
|
||||
int segmentNumber,
|
||||
boolean lastSegment,
|
||||
byte[] transactionId) {
|
||||
super(session);
|
||||
this.type = type;
|
||||
this.name = name;
|
||||
this.segmentNumber = segmentNumber;
|
||||
this.lastSegment = lastSegment;
|
||||
this.transactionId = transactionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
SignedInfo signedInfo;
|
||||
|
||||
buildTransfer();
|
||||
signedInfo = new SignedInfo(session.getUser(), getDigest());
|
||||
signedInfo.build();
|
||||
((EbicsRequestDocument) document)
|
||||
.getEbicsRequest()
|
||||
.setAuthSignature(signedInfo.getSignatureType());
|
||||
((EbicsRequestDocument) document)
|
||||
.getEbicsRequest()
|
||||
.getAuthSignature()
|
||||
.setSignatureValue(
|
||||
EbicsXmlFactory.createSignatureValueType(signedInfo.sign(toByteArray())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name + ".xml";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the digest value of the authenticated XML portions.
|
||||
*
|
||||
* @return the digest value.
|
||||
* @throws EbicsException Failed to retrieve the digest value.
|
||||
*/
|
||||
public byte[] getDigest() throws AxelorException {
|
||||
addNamespaceDecl("ds", "http://www.w3.org/2000/09/xmldsig#");
|
||||
|
||||
try {
|
||||
return MessageDigest.getInstance("SHA-256", "BC").digest(EbicsUtils.canonize(toByteArray()));
|
||||
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(), TraceBackRepository.CATEGORY_CONFIGURATION_ERROR, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the order type of the element.
|
||||
*
|
||||
* @return the order type element.
|
||||
*/
|
||||
public String getOrderType() {
|
||||
return type.getOrderType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
setSaveSuggestedPrefixes("http://www.ebics.org/H003", XMLConstants.DEFAULT_NS_PREFIX);
|
||||
|
||||
return super.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the transfer request.
|
||||
*
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public abstract void buildTransfer() throws AxelorException;
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
protected int segmentNumber;
|
||||
protected boolean lastSegment;
|
||||
protected byte[] transactionId;
|
||||
private OrderType type;
|
||||
private String name;
|
||||
}
|
||||
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsResponseDocument;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsResponseDocument.EbicsResponse;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.exception.ReturnCode;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
/**
|
||||
* The <code>TransferResponseElement</code> is the common element response for all ebics transfers.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class TransferResponseElement extends DefaultResponseElement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>TransferResponseElement</code> element.
|
||||
*
|
||||
* @param factory the content factory
|
||||
* @param orderType the order type
|
||||
* @param name the element name;
|
||||
*/
|
||||
public TransferResponseElement(ContentFactory factory, String name, EbicsUser ebicsUser) {
|
||||
super(factory, name, ebicsUser);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
String code;
|
||||
String text;
|
||||
|
||||
parse(factory);
|
||||
response = ((EbicsResponseDocument) document).getEbicsResponse();
|
||||
code = response.getHeader().getMutable().getReturnCode();
|
||||
text = response.getHeader().getMutable().getReportText();
|
||||
returnCode = ReturnCode.toReturnCode(code, text);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
protected EbicsResponse response;
|
||||
}
|
||||
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.DataEncryptionInfoType.EncryptionPubKeyDigest;
|
||||
import com.axelor.apps.account.ebics.schema.h003.DataTransferRequestType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.DataTransferRequestType.DataEncryptionInfo;
|
||||
import com.axelor.apps.account.ebics.schema.h003.DataTransferRequestType.SignatureData;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Body;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Header;
|
||||
import com.axelor.apps.account.ebics.schema.h003.FULOrderParamsType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.FileFormatType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.MutableHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.ParameterDocument.Parameter;
|
||||
import com.axelor.apps.account.ebics.schema.h003.ParameterDocument.Parameter.Value;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderOrderDetailsType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderOrderDetailsType.OrderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.BankPubKeyDigests;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.BankPubKeyDigests.Authentication;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.BankPubKeyDigests.Encryption;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType.Product;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsPartnerRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.certificate.KeyUtil;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsUtils;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderAttribute;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.apps.bankpayment.ebics.io.Splitter;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.xml.XMLConstants;
|
||||
import org.jdom.JDOMException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The <code>UInitializationRequestElement</code> is the common initialization element for all ebics
|
||||
* file uploads.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class UInitializationRequestElement extends InitializationRequestElement {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
/**
|
||||
* Constructs a new <code>UInitializationRequestElement</code> for uploads initializations.
|
||||
*
|
||||
* @param session the current ebics session.
|
||||
* @param orderType the upload order type
|
||||
* @param userData the user data to be uploaded
|
||||
* @throws EbicsException
|
||||
*/
|
||||
public UInitializationRequestElement(
|
||||
EbicsSession session,
|
||||
com.axelor.apps.bankpayment.ebics.client.OrderType orderType,
|
||||
byte[] userData,
|
||||
byte[] userSignatureData)
|
||||
throws AxelorException {
|
||||
super(session, orderType, generateName(orderType));
|
||||
this.userData = userData;
|
||||
this.userSignatureData = userSignatureData;
|
||||
keySpec = new SecretKeySpec(nonce, "EAS");
|
||||
splitter = new Splitter(userData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildInitialization() throws AxelorException {
|
||||
EbicsRequest request;
|
||||
Header header;
|
||||
Body body;
|
||||
MutableHeaderType mutable;
|
||||
StaticHeaderType xstatic;
|
||||
Product product;
|
||||
BankPubKeyDigests bankPubKeyDigests;
|
||||
Authentication authentication;
|
||||
Encryption encryption;
|
||||
DataTransferRequestType dataTransfer;
|
||||
DataEncryptionInfo dataEncryptionInfo;
|
||||
SignatureData signatureData;
|
||||
EncryptionPubKeyDigest encryptionPubKeyDigest;
|
||||
StaticHeaderOrderDetailsType orderDetails;
|
||||
FULOrderParamsType fULOrderParams;
|
||||
OrderType orderType;
|
||||
FileFormatType fileFormat;
|
||||
List<Parameter> parameters;
|
||||
|
||||
EbicsUser ebicsUser = session.getUser();
|
||||
EbicsPartner ebicsPartner = ebicsUser.getEbicsPartner();
|
||||
|
||||
if (ebicsPartner.getEbicsTypeSelect() == EbicsPartnerRepository.EBICS_TYPE_TS) {
|
||||
|
||||
EbicsUser signatoryUser = session.getSignatoryUser();
|
||||
|
||||
userSignature =
|
||||
new UserSignature(
|
||||
signatoryUser, generateName("UserSignature"), "A005", userData, userSignatureData);
|
||||
} else {
|
||||
userSignature =
|
||||
new UserSignature(ebicsUser, generateName("UserSignature"), "A005", userData, null);
|
||||
}
|
||||
|
||||
userSignature.build();
|
||||
|
||||
log.debug("user signature pretty print : {}", userSignature.toString());
|
||||
|
||||
userSignature.validate();
|
||||
|
||||
log.debug("user signature pretty print : {}", userSignature.toString());
|
||||
|
||||
splitter.readInput(true, keySpec);
|
||||
|
||||
mutable = EbicsXmlFactory.createMutableHeaderType("Initialisation", null);
|
||||
product =
|
||||
EbicsXmlFactory.createProduct(
|
||||
session.getProduct().getLanguage(), session.getProduct().getName());
|
||||
authentication =
|
||||
EbicsXmlFactory.createAuthentication(
|
||||
"X002",
|
||||
"http://www.w3.org/2001/04/xmlenc#sha256",
|
||||
decodeHex(KeyUtil.getKeyDigest(session.getBankX002Key())));
|
||||
encryption =
|
||||
EbicsXmlFactory.createEncryption(
|
||||
"E002",
|
||||
"http://www.w3.org/2001/04/xmlenc#sha256",
|
||||
decodeHex(KeyUtil.getKeyDigest(session.getBankE002Key())));
|
||||
bankPubKeyDigests = EbicsXmlFactory.createBankPubKeyDigests(authentication, encryption);
|
||||
orderType = EbicsXmlFactory.createOrderType(type.getOrderType());
|
||||
fileFormat =
|
||||
EbicsXmlFactory.createFileFormatType(
|
||||
Locale.FRANCE.getCountry(), session.getSessionParam("FORMAT"));
|
||||
fULOrderParams = EbicsXmlFactory.createFULOrderParamsType(fileFormat);
|
||||
parameters = new ArrayList<Parameter>();
|
||||
if (Boolean.valueOf(session.getSessionParam("TEST")).booleanValue()) {
|
||||
Parameter parameter;
|
||||
Value value;
|
||||
|
||||
value = EbicsXmlFactory.createValue("String", "TRUE");
|
||||
parameter = EbicsXmlFactory.createParameter("TEST", value);
|
||||
parameters.add(parameter);
|
||||
}
|
||||
|
||||
if (Boolean.valueOf(session.getSessionParam("EBCDIC")).booleanValue()) {
|
||||
Parameter parameter;
|
||||
Value value;
|
||||
|
||||
value = EbicsXmlFactory.createValue("String", "TRUE");
|
||||
parameter = EbicsXmlFactory.createParameter("EBCDIC", value);
|
||||
parameters.add(parameter);
|
||||
}
|
||||
|
||||
if (parameters.size() > 0) {
|
||||
fULOrderParams.setParameterArray(parameters.toArray(new Parameter[parameters.size()]));
|
||||
}
|
||||
|
||||
OrderAttribute orderAttribute = new OrderAttribute(type, ebicsPartner.getEbicsTypeSelect());
|
||||
orderAttribute.build();
|
||||
|
||||
orderDetails =
|
||||
EbicsXmlFactory.createStaticHeaderOrderDetailsType(
|
||||
ebicsUser.getNextOrderId(),
|
||||
orderAttribute.getOrderAttributes(),
|
||||
orderType,
|
||||
fULOrderParams);
|
||||
xstatic =
|
||||
EbicsXmlFactory.createStaticHeaderType(
|
||||
session.getBankID(),
|
||||
nonce,
|
||||
splitter.getSegmentNumber(),
|
||||
ebicsPartner.getPartnerId(),
|
||||
product,
|
||||
ebicsUser.getSecurityMedium(),
|
||||
ebicsUser.getUserId(),
|
||||
Calendar.getInstance(),
|
||||
orderDetails,
|
||||
bankPubKeyDigests);
|
||||
header = EbicsXmlFactory.createEbicsRequestHeader(true, mutable, xstatic);
|
||||
encryptionPubKeyDigest =
|
||||
EbicsXmlFactory.createEncryptionPubKeyDigest(
|
||||
"E002",
|
||||
"http://www.w3.org/2001/04/xmlenc#sha256",
|
||||
decodeHex(KeyUtil.getKeyDigest(session.getBankE002Key())));
|
||||
|
||||
System.out.println(
|
||||
"signature ----------------------------------------------------------------------------");
|
||||
System.out.println(userSignature.toString());
|
||||
|
||||
// USE PREVALIDATION
|
||||
// PreValidation preValidation = PreValidation.Factory.newInstance();
|
||||
// preValidation.setAuthenticate(true);
|
||||
// DataDigestType dataDigest = DataDigestType.Factory.newInstance();
|
||||
// dataDigest.setSignatureVersion("A005");
|
||||
// dataDigest.setStringValue("XXXXXXX);
|
||||
// preValidation.setDataDigestArray(new DataDigestType[] {dataDigest});
|
||||
|
||||
signatureData =
|
||||
EbicsXmlFactory.createSignatureData(
|
||||
true, EbicsUtils.encrypt(EbicsUtils.zip(userSignature.prettyPrint()), keySpec));
|
||||
|
||||
dataEncryptionInfo =
|
||||
EbicsXmlFactory.createDataEncryptionInfo(
|
||||
true, encryptionPubKeyDigest, generateTransactionKey());
|
||||
dataTransfer = EbicsXmlFactory.createDataTransferRequestType(dataEncryptionInfo, signatureData);
|
||||
|
||||
// USE PREVALIDATION
|
||||
// body = EbicsXmlFactory.createEbicsRequestBody(dataTransfer, preValidation);
|
||||
|
||||
body = EbicsXmlFactory.createEbicsRequestBody(dataTransfer);
|
||||
|
||||
request = EbicsXmlFactory.createEbicsRequest(1, "H003", header, body);
|
||||
document = EbicsXmlFactory.createEbicsRequestDocument(request);
|
||||
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
try {
|
||||
this.save(bout);
|
||||
} catch (JDOMException e) {
|
||||
// TODO Bloc catch généré automatiquement
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println(
|
||||
"Requete signature ----------------------------------------------------------------------------");
|
||||
System.out.println(bout.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
setSaveSuggestedPrefixes("http://www.ebics.org/H003", XMLConstants.DEFAULT_NS_PREFIX);
|
||||
|
||||
return super.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the user signature data.
|
||||
*
|
||||
* @return the user signature data.
|
||||
*/
|
||||
public UserSignature getUserSignature() {
|
||||
return userSignature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content of a given segment.
|
||||
*
|
||||
* @param segment the segment number
|
||||
* @return the content of the given segment
|
||||
*/
|
||||
public ContentFactory getContent(int segment) {
|
||||
return splitter.getContent(segment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total segment number.
|
||||
*
|
||||
* @return the total segment number.
|
||||
*/
|
||||
public int getSegmentNumber() {
|
||||
return splitter.getSegmentNumber();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private byte[] userData;
|
||||
private byte[] userSignatureData;
|
||||
private UserSignature userSignature;
|
||||
private SecretKeySpec keySpec;
|
||||
private Splitter splitter;
|
||||
}
|
||||
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.h003.DataTransferRequestType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.DataTransferRequestType.OrderData;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Body;
|
||||
import com.axelor.apps.account.ebics.schema.h003.EbicsRequestDocument.EbicsRequest.Header;
|
||||
import com.axelor.apps.account.ebics.schema.h003.MutableHeaderType;
|
||||
import com.axelor.apps.account.ebics.schema.h003.MutableHeaderType.SegmentNumber;
|
||||
import com.axelor.apps.account.ebics.schema.h003.StaticHeaderType;
|
||||
import com.axelor.apps.bankpayment.ebics.client.EbicsSession;
|
||||
import com.axelor.apps.bankpayment.ebics.client.OrderType;
|
||||
import com.axelor.apps.bankpayment.ebics.interfaces.ContentFactory;
|
||||
import com.axelor.apps.bankpayment.ebics.io.IOUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import org.jdom.JDOMException;
|
||||
|
||||
/**
|
||||
* The <code>UTransferRequestElement</code> is the root element for all ebics upload transfers.
|
||||
*
|
||||
* @author Hachani
|
||||
*/
|
||||
public class UTransferRequestElement extends TransferRequestElement {
|
||||
|
||||
/**
|
||||
* Constructs a new <code>UTransferRequestElement</code> for ebics upload transfer.
|
||||
*
|
||||
* @param session the current ebics session
|
||||
* @param orderType the upload order type
|
||||
* @param segmentNumber the segment number
|
||||
* @param lastSegment i it the last segment?
|
||||
* @param transactionId the transaction ID
|
||||
* @param content the content factory
|
||||
*/
|
||||
public UTransferRequestElement(
|
||||
EbicsSession session,
|
||||
OrderType orderType,
|
||||
int segmentNumber,
|
||||
boolean lastSegment,
|
||||
byte[] transactionId,
|
||||
ContentFactory content) {
|
||||
super(session, generateName(orderType), orderType, segmentNumber, lastSegment, transactionId);
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildTransfer() throws AxelorException {
|
||||
EbicsRequest request;
|
||||
Header header;
|
||||
Body body;
|
||||
MutableHeaderType mutable;
|
||||
SegmentNumber segmentNumber;
|
||||
StaticHeaderType xstatic;
|
||||
OrderData orderData;
|
||||
DataTransferRequestType dataTransfer;
|
||||
|
||||
segmentNumber = EbicsXmlFactory.createSegmentNumber(this.segmentNumber, lastSegment);
|
||||
mutable = EbicsXmlFactory.createMutableHeaderType("Transfer", segmentNumber);
|
||||
xstatic = EbicsXmlFactory.createStaticHeaderType(session.getBankID(), transactionId);
|
||||
header = EbicsXmlFactory.createEbicsRequestHeader(true, mutable, xstatic);
|
||||
orderData = EbicsXmlFactory.createEbicsRequestOrderData(IOUtils.getFactoryContent(content));
|
||||
dataTransfer = EbicsXmlFactory.createDataTransferRequestType(orderData);
|
||||
body = EbicsXmlFactory.createEbicsRequestBody(dataTransfer); // TODO CHECK
|
||||
request = EbicsXmlFactory.createEbicsRequest(1, "H003", header, body);
|
||||
document = EbicsXmlFactory.createEbicsRequestDocument(request);
|
||||
|
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream();
|
||||
try {
|
||||
this.save(bout);
|
||||
} catch (JDOMException e) {
|
||||
// TODO Bloc catch généré automatiquement
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
System.out.println(
|
||||
"Requete data ----------------------------------------------------------------------------");
|
||||
System.out.println(bout.toString());
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// DATA MEMBERS
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
private ContentFactory content;
|
||||
}
|
||||
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.account.ebics.schema.s001.OrderSignatureDataType;
|
||||
import com.axelor.apps.account.ebics.schema.s001.UserSignatureDataSigBookType;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsPartnerRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsUserService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.inject.Beans;
|
||||
import java.util.Base64;
|
||||
import javax.xml.XMLConstants;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A root EBICS element representing the user signature element. The user data is signed with the
|
||||
* user signature key sent in the INI request to the EBICS bank server
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class UserSignature extends DefaultEbicsRootElement {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private EbicsUser user;
|
||||
private String signatureVersion;
|
||||
private byte[] data;
|
||||
private byte[] signature;
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>UserSignature</code> element for an Ebics user and a data to sign
|
||||
*
|
||||
* @param user the ebics user
|
||||
* @param signatureVersion the signature version
|
||||
* @param toSign the data to be signed
|
||||
*/
|
||||
public UserSignature(
|
||||
EbicsUser user, String name, String signatureVersion, byte[] data, byte[] signature) {
|
||||
this.user = user;
|
||||
this.data = data;
|
||||
this.signature = signature;
|
||||
this.name = name;
|
||||
this.signatureVersion = signatureVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void build() throws AxelorException {
|
||||
UserSignatureDataSigBookType userSignatureData;
|
||||
OrderSignatureDataType orderSignatureData;
|
||||
|
||||
try {
|
||||
|
||||
if (user.getEbicsPartner().getEbicsTypeSelect() == EbicsPartnerRepository.EBICS_TYPE_TS) {
|
||||
|
||||
log.debug("Signature (base64) : {}", new String(signature));
|
||||
log.debug("Signature (base64) length : {}", signature.length);
|
||||
|
||||
signature = EbicsUserService.removeOSSpecificChars(signature);
|
||||
|
||||
log.debug(
|
||||
"Signature (base64) length after remove OS specific chars : {}", signature.length);
|
||||
|
||||
signature = Base64.getDecoder().decode(signature);
|
||||
|
||||
log.debug("Signature (byte) length : {}", signature.length);
|
||||
|
||||
} else {
|
||||
signature = Beans.get(EbicsUserService.class).sign(user, data);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
UserSignatureVerify userSignatureVerify = new UserSignatureVerify(user, data, signature);
|
||||
userSignatureVerify.verify();
|
||||
|
||||
/**
|
||||
* Include certificate informations
|
||||
*
|
||||
* <p>EbicsCertificate ebicsEertificate = user.getA005Certificate();
|
||||
*
|
||||
* <p>X509DataType x509Data = EbicsXmlFactory.createX509DataType(ebicsEertificate.getSubject(),
|
||||
* ebicsEertificate.getCertificate(), ebicsEertificate.getIssuer(), new
|
||||
* BigInteger(ebicsEertificate.getSerial(), 16));
|
||||
*
|
||||
* <p>orderSignatureData = EbicsXmlFactory.createOrderSignatureDataType(signatureVersion,
|
||||
* user.getEbicsPartner().getPartnerId(), user.getUserId(), signature, x509Data); *
|
||||
*/
|
||||
orderSignatureData =
|
||||
EbicsXmlFactory.createOrderSignatureDataType(
|
||||
signatureVersion, user.getEbicsPartner().getPartnerId(), user.getUserId(), signature);
|
||||
userSignatureData =
|
||||
EbicsXmlFactory.createUserSignatureDataSigBookType(
|
||||
new OrderSignatureDataType[] {orderSignatureData});
|
||||
document = EbicsXmlFactory.createUserSignatureDataDocument(userSignatureData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name + ".xml";
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] toByteArray() {
|
||||
addNamespaceDecl("xsi", "http://www.w3.org/2001/XMLSchema-instance");
|
||||
|
||||
setSaveSuggestedPrefixes("http://www.ebics.org/S001", XMLConstants.DEFAULT_NS_PREFIX);
|
||||
|
||||
insertSchemaLocation(
|
||||
"http://www.w3.org/2001/XMLSchema-instance",
|
||||
"schemaLocation",
|
||||
"xsi",
|
||||
"http://www.ebics.org/S001 http://www.ebics.org/S001/ebics_signature.xsd");
|
||||
|
||||
return super.toByteArray();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.ebics.xml;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.EbicsCertificate;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsUserService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import java.math.BigInteger;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A root EBICS element representing the user signature element. The user data is signed with the
|
||||
* user signature key sent in the INI request to the EBICS bank server
|
||||
*
|
||||
* @author hachani
|
||||
*/
|
||||
public class UserSignatureVerify {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private EbicsUser user;
|
||||
private byte[] signature;
|
||||
private byte[] bankOrderContent;
|
||||
private String modulus;
|
||||
private String exponent;
|
||||
|
||||
/**
|
||||
* Constructs a new <code>UserSignature</code> element for an Ebics user and a data to sign
|
||||
*
|
||||
* @param user the ebics user
|
||||
* @param signatureVersion the signature version
|
||||
* @param toSign the data to be signed
|
||||
*/
|
||||
public UserSignatureVerify(EbicsUser user, byte[] bankOrderContent, byte[] signature) {
|
||||
this.user = user;
|
||||
this.bankOrderContent = bankOrderContent;
|
||||
this.signature = signature;
|
||||
loadCertificate();
|
||||
}
|
||||
|
||||
public void verify() throws AxelorException {
|
||||
|
||||
String comptedSha256Digest = computeSha256Digest();
|
||||
String originalDigestFromSignature = getOriginalDigestFromSignature();
|
||||
if (!comptedSha256Digest.equals(originalDigestFromSignature)) {
|
||||
String message =
|
||||
I18n.get(
|
||||
"Computed digest (SHA256) of the bank order file doesn't match with the digest extract from the signature")
|
||||
+ " \n";
|
||||
message +=
|
||||
I18n.get("Computed digest (SHA256) of the bank order file :")
|
||||
+ " "
|
||||
+ comptedSha256Digest
|
||||
+ "\n";
|
||||
message +=
|
||||
I18n.get("Original digest extracted from the signature :")
|
||||
+ " "
|
||||
+ originalDigestFromSignature;
|
||||
throw new AxelorException(message, TraceBackRepository.CATEGORY_INCONSISTENCY);
|
||||
}
|
||||
}
|
||||
|
||||
public void loadCertificate() {
|
||||
|
||||
EbicsCertificate certificate = user.getA005Certificate();
|
||||
|
||||
this.modulus = certificate.getPublicKeyModulus();
|
||||
this.exponent = certificate.getPublicKeyExponent();
|
||||
}
|
||||
|
||||
public String computeSha256Digest() {
|
||||
|
||||
bankOrderContent = EbicsUserService.removeOSSpecificChars(bankOrderContent);
|
||||
|
||||
String sha = DigestUtils.sha256Hex(bankOrderContent);
|
||||
|
||||
log.debug("Digest (SHA256) of bank order content : {}", sha);
|
||||
|
||||
return sha;
|
||||
}
|
||||
|
||||
public String getOriginalDigestFromSignature() {
|
||||
|
||||
String hexSignature = getHexSignature();
|
||||
|
||||
System.out.println("Signature (HEX STRING) : " + hexSignature);
|
||||
|
||||
String result =
|
||||
new BigInteger(hexSignature, 16)
|
||||
.modPow(new BigInteger(exponent, 16), new BigInteger(modulus, 16))
|
||||
.toString(16);
|
||||
|
||||
log.debug("Orignal digest from signature (with padding) : {}", result);
|
||||
|
||||
result = result.substring(result.length() - 64, result.length());
|
||||
|
||||
log.debug("Orignal digest from signature : {}", result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getHexSignature() {
|
||||
|
||||
return Hex.encodeHexString(signature);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.exception;
|
||||
|
||||
/**
|
||||
* Interface of Exceptions. Enum all exception of axelor-account.
|
||||
*
|
||||
* @author dubaux
|
||||
*/
|
||||
public interface IExceptionMessage {
|
||||
|
||||
/** Bank statement service */
|
||||
static final String BANK_STATEMENT_1 = /*$$(*/
|
||||
"%s : Computed balance and Ending Balance must be equal" /*)*/;
|
||||
|
||||
static final String BANK_STATEMENT_2 = /*$$(*/
|
||||
"%s : MoveLine amount is not equals with bank statement line %s" /*)*/;
|
||||
static final String BANK_STATEMENT_3 = /*$$(*/
|
||||
"%s : Bank statement line %s amount can't be null" /*)*/;
|
||||
|
||||
/** Account config Bank Payment Service */
|
||||
static final String ACCOUNT_CONFIG_41 = /*$$(*/
|
||||
"%s : Please, configure a default signer for the company %s" /*)*/;
|
||||
|
||||
static final String ACCOUNT_CONFIG_1 = /*$$(*/
|
||||
"%s : You must configure bank payment's information for the company %s" /*)*/;
|
||||
static final String ACCOUNT_CONFIG_SEQUENCE_5 = /*$$(*/
|
||||
"%s : Please, configure a sequence for the SEPA Credit Transfers and the company %s" /*)*/;
|
||||
static final String ACCOUNT_CONFIG_SEQUENCE_6 = /*$$(*/
|
||||
"%s : Please, configure a sequence for the SEPA Direct Debits and the company %s" /*)*/;
|
||||
static final String ACCOUNT_CONFIG_SEQUENCE_7 = /*$$(*/
|
||||
"%s : Please, configure a sequence for the International Credit Transfers and the company %s" /*)*/;
|
||||
static final String ACCOUNT_CONFIG_SEQUENCE_8 = /*$$(*/
|
||||
"%s : Please, configure a sequence for the International Direct Debits and the company %s" /*)*/;
|
||||
static final String ACCOUNT_CONFIG_SEQUENCE_9 = /*$$(*/
|
||||
"%s : Please, configure a sequence for the International Treasury Transfers and the company %s" /*)*/;
|
||||
static final String ACCOUNT_CONFIG_SEQUENCE_10 = /*$$(*/
|
||||
"%s : Please, configure a sequence for the National Treasury Transfers and the company %s" /*)*/;
|
||||
static final String ACCOUNT_CONFIG_SEQUENCE_11 = /*$$(*/
|
||||
"%s : Please, configure a sequence for the Other Bank Orders and the company %s" /*)*/;
|
||||
|
||||
static final String ACCOUNT_CONFIG_EXTERNAL_BANK_TO_BANK_ACCOUNT = /*$$(*/
|
||||
"%s : Please, configure an account for the bank order for the external bank to bank transfer for the company %s" /*)*/;
|
||||
static final String ACCOUNT_CONFIG_INTERNAL_BANK_TO_BANK_ACCOUNT = /*$$(*/
|
||||
"%s : Please, configure an account for the bank order for the internal bank to bank transfer for the company %s" /*)*/;
|
||||
|
||||
static final String ACCOUNT_CONFIG_MISSING_ICS_NUMBER = /*$$(*/
|
||||
"%s : Please configure an ICS number for the company %s." /*)*/;
|
||||
|
||||
/** BankOrder service */
|
||||
static final String BANK_ORDER_DATE = /*$$(*/ "Bank Order date can't be in the past" /*)*/;
|
||||
|
||||
static final String BANK_ORDER_DATE_MISSING = /*$$(*/ "Please fill bank order date" /*)*/;
|
||||
static final String BANK_ORDER_TYPE_MISSING = /*$$(*/ "Please fill bank order type" /*)*/;
|
||||
static final String BANK_ORDER_PARTNER_TYPE_MISSING = /*$$(*/
|
||||
"Please fill partner type for the bank order" /*)*/;
|
||||
static final String BANK_ORDER_COMPANY_MISSING = /*$$(*/ "Please fill the sender company" /*)*/;
|
||||
static final String BANK_ORDER_BANK_DETAILS_MISSING = /*$$(*/
|
||||
"Please fill the bank details" /*)*/;
|
||||
static final String BANK_ORDER_CURRENCY_MISSING = /*$$(*/
|
||||
"Please fill currency for the bank order" /*)*/;
|
||||
static final String BANK_ORDER_AMOUNT_NEGATIVE = /*$$(*/
|
||||
"Amount value of the bank order is not valid" /*)*/;
|
||||
static final String BANK_ORDER_PAYMENT_MODE_MISSING = /*$$(*/
|
||||
"Please select a payment mode" /*)*/;
|
||||
static final String BANK_ORDER_SIGNATORY_MISSING = /*$$(*/ "Please select a signatory" /*)*/;
|
||||
static final String BANK_ORDER_WRONG_SENDER_RECORD = /*$$(*/
|
||||
"Anomaly has been detected during file generation for the sender record of the bank order %s" /*)*/;
|
||||
static final String BANK_ORDER_WRONG_MAIN_DETAIL_RECORD = /*$$(*/
|
||||
"Anomaly has been detected during file generation for the detail record of the bank order line %s" /*)*/;
|
||||
static final String BANK_ORDER_WRONG_BENEFICIARY_BANK_DETAIL_RECORD = /*$$(*/
|
||||
"Anomaly has been detected during file generation for the beneficiary bank detail record of the bank order line %s" /*)*/;
|
||||
static final String BANK_ORDER_WRONG_FURTHER_INFORMATION_DETAIL_RECORD = /*$$(*/
|
||||
"Anomaly has been detected during file generation for the further information detail record of the bank order line %s" /*)*/;
|
||||
static final String BANK_ORDER_WRONG_TOTAL_RECORD = /*$$(*/
|
||||
"Anomaly has been detected during file generation for the total record of the bank order %s" /*)*/;
|
||||
static final String BANK_ORDER_ISSUE_DURING_FILE_GENERATION = /*$$(*/
|
||||
"Anomaly has been detected during file generation for bank order %s" /*)*/;
|
||||
static final String BANK_ORDER_COMPANY_NO_SEQUENCE = /*$$(*/
|
||||
"The company %s does not have bank order sequence" /*)*/;
|
||||
static final String BANK_ORDER_BANK_DETAILS_EMPTY_IBAN = /*$$(*/
|
||||
"The Iban is mandatory for the partner %s, bank order %s" /*)*/;
|
||||
static final String BANK_ORDER_BANK_DETAILS_NOT_ACTIVE = /*$$(*/
|
||||
"The bank details is inactive." /*)*/;
|
||||
static final String BANK_ORDER_BANK_DETAILS_TYPE_NOT_COMPATIBLE = /*$$(*/
|
||||
"The bank details type is not compatible with the accepted types in file format." /*)*/;
|
||||
static final String BANK_ORDER_BANK_DETAILS_CURRENCY_NOT_COMPATIBLE = /*$$(*/
|
||||
"The sender bank details currency is not compatible with the currency in bank order." /*)*/;
|
||||
static final String BANK_ORDER_BANK_DETAILS_MISSING_CURRENCY = /*$$(*/
|
||||
"Please fill the sender bank details currency." /*)*/;
|
||||
static final String BANK_ORDER_NOT_PROPERLY_SIGNED = /*$$(*/
|
||||
"The bank order is not properly signed. Please correct it and sign it again." /*)*/;
|
||||
static final String BANK_ORDER_CANNOT_REMOVE = /*$$(*/
|
||||
"Bank orders can only be deleted at draft or canceled status." /*)*/;
|
||||
|
||||
String BANK_ORDER_RECEIVER_BANK_DETAILS_MISSING_BANK_ADDRESS = /*$$(*/
|
||||
"Please fill the bank address in the receiver bank details." /*)*/;
|
||||
String BANK_ORDER_RECEIVER_BANK_DETAILS_MISSING_BANK = /*$$(*/
|
||||
"Please fill the bank in the receiver bank details." /*)*/;
|
||||
|
||||
/** BankOrder lines */
|
||||
static final String BANK_ORDER_LINES_MISSING = /*$$(*/
|
||||
"You can't validate this bank order. you need to fill at least one bank order line" /*)*/;
|
||||
|
||||
static final String BANK_ORDER_LINE_COMPANY_MISSING = /*$$(*/
|
||||
"Please select a company for the bank order lines inserted" /*)*/;
|
||||
static final String BANK_ORDER_LINE_PARTNER_MISSING = /*$$(*/
|
||||
"Please select a partner for the bank order lines inserted" /*)*/;
|
||||
static final String BANK_ORDER_LINE_AMOUNT_NEGATIVE = /*$$(*/
|
||||
"Amount value of a bank order line is not valid" /*)*/;
|
||||
static final String BANK_ORDER_LINE_TOTAL_AMOUNT_INVALID = /*$$(*/
|
||||
"Total amount of bank order lines must be equal to the bank order amount" /*)*/;
|
||||
static final String BANK_ORDER_LINE_BANK_DETAILS_MISSING = /*$$(*/
|
||||
"Please fill the receiver bank details" /*)*/;
|
||||
static final String BANK_ORDER_LINE_BANK_DETAILS_FORBIDDEN = /*$$(*/
|
||||
"You cannot use this bank account because he is not authorized by the ebics partner." /*)*/;
|
||||
static final String BANK_ORDER_LINE_BANK_DETAILS_NOT_ACTIVE = /*$$(*/
|
||||
"The receiver bank details is inactive." /*)*/;
|
||||
static final String BANK_ORDER_LINE_BANK_DETAILS_TYPE_NOT_COMPATIBLE = /*$$(*/
|
||||
"The receiver bank details type is not compatible with the accepted types in file format." /*)*/;
|
||||
static final String BANK_ORDER_LINE_BANK_DETAILS_CURRENCY_NOT_COMPATIBLE = /*$$(*/
|
||||
"The receiver bank details currency is not compatible with the currency in bank order." /*)*/;
|
||||
static final String BANK_ORDER_LINE_NO_RECEIVER_ADDRESS = /*$$(*/
|
||||
"No address has been defined in the receiver %s" /*)*/;
|
||||
|
||||
/** BankOrder merge */
|
||||
static final String BANK_ORDER_MERGE_AT_LEAST_TWO_BANK_ORDERS = /*$$(*/
|
||||
"Please select at least two bank orders" /*)*/;
|
||||
|
||||
static final String BANK_ORDER_MERGE_STATUS = /*$$(*/
|
||||
"Please select draft or awaiting signature bank orders only" /*)*/;
|
||||
static final String BANK_ORDER_MERGE_SAME_STATUS = /*$$(*/
|
||||
"Please select some bank orders that have the same status" /*)*/;
|
||||
static final String BANK_ORDER_MERGE_SAME_ORDER_TYPE_SELECT = /*$$(*/
|
||||
"Please select some bank orders that have the same status" /*)*/;
|
||||
static final String BANK_ORDER_MERGE_SAME_PAYMENT_MODE = /*$$(*/
|
||||
"Please select some bank orders that have the same payment mode" /*)*/;
|
||||
static final String BANK_ORDER_MERGE_SAME_PARTNER_TYPE_SELECT = /*$$(*/
|
||||
"Please select some bank orders that have the same partner type" /*)*/;
|
||||
static final String BANK_ORDER_MERGE_SAME_SENDER_COMPANY = /*$$(*/
|
||||
"Please select some bank orders that have the same sender company" /*)*/;
|
||||
static final String BANK_ORDER_MERGE_SAME_SENDER_BANK_DETAILS = /*$$(*/
|
||||
"Please select some bank orders that have the same sender bank details" /*)*/;
|
||||
static final String BANK_ORDER_MERGE_SAME_CURRENCY = /*$$(*/
|
||||
"Please select some bank orders that have the same currency" /*)*/;
|
||||
static final String BANK_ORDER_MERGE_NO_BANK_ORDERS = /*$$(*/ "No bank orders found" /*)*/;
|
||||
|
||||
/** BankOrder file */
|
||||
static final String BANK_ORDER_FILE_NO_SENDER_ADDRESS = /*$$(*/
|
||||
"No address has been defined in the sender company %s" /*)*/;
|
||||
|
||||
static final String BANK_ORDER_FILE_NO_FOLDER_PATH = /*$$(*/
|
||||
"No folder path has been defined in the payment mode %s" /*)*/;
|
||||
static final String BANK_ORDER_FILE_UNKNOWN_FORMAT = /*$$(*/
|
||||
"Unknown format for file generation" /*)*/;
|
||||
static final String BANK_ORDER_FILE_UNKNOWN_SEPA_TYPE = /*$$(*/
|
||||
"Unknown SEPA type for file generation" /*)*/;
|
||||
|
||||
/** Ebics */
|
||||
static final String EBICS_WRONG_PASSWORD = /*$$(*/ "Incorrect password, please try again" /*)*/;
|
||||
|
||||
static final String EBICS_MISSING_PASSWORD = /*$$(*/ "Please insert a password" /*)*/;
|
||||
static final String EBICS_MISSING_NAME = /*$$(*/ "Please select a user name" /*)*/;
|
||||
static final String EBICS_TEST_MODE_NOT_ENABLED = /*$$(*/
|
||||
"Test mode is not enabled or test file is missing" /*)*/;
|
||||
static final String EBICS_MISSING_CERTIFICATES = /*$$(*/ "Please add certificates to print" /*)*/;
|
||||
static final String EBICS_INVALID_BANK_URL = /*$$(*/
|
||||
"Invalid bank url. It must be start with http:// or https://" /*)*/;
|
||||
static final String EBICS_MISSING_USER_TRANSPORT = /*$$(*/
|
||||
"Please insert a EBICS user for transport in the EBICS partner" /*)*/;
|
||||
static final String EBICS_NO_SERVICE_CONFIGURED = /*$$(*/
|
||||
"No service configured on EBICS partner %s for file format %s" /*)*/;
|
||||
static final String EBICS_PARTNER_BANK_DETAILS_WARNING = /*$$(*/
|
||||
"At least one bank details you have entered is missing currency. Here is the list of invalid bank details : %s" /*)*/;
|
||||
static final String EBICS_MISSING_SIGNATORY_EBICS_USER = /* $$( */
|
||||
"Signatory EBICS user is missing." /* ) */;
|
||||
|
||||
/** Batch bank statement */
|
||||
String BATCH_BANK_STATEMENT_RETRIEVED_BANK_STATEMENT_COUNT = /*$$(*/
|
||||
"Number of retrieved bank statements: %d." /*)*/;
|
||||
|
||||
/** BankStatement import */
|
||||
static final String BANK_STATEMENT_FILE_UNKNOWN_FORMAT = /*$$(*/
|
||||
"Unknown format for file import process" /*)*/;
|
||||
|
||||
static final String BANK_STATEMENT_MISSING_FILE = /*$$(*/ "Missing bank statement file" /*)*/;
|
||||
static final String BANK_STATEMENT_MISSING_FILE_FORMAT = /*$$(*/
|
||||
"Missing bank statement file format" /*)*/;
|
||||
static final String BANK_STATEMENT_EBICS_PARTNER = /*$$(*/
|
||||
"Error with EBICS partner %s: %s" /*)*/;
|
||||
|
||||
/*
|
||||
* Batch direct debit
|
||||
*/
|
||||
static final String BATCH_DIRECT_DEBIT_MISSING_COMPANY_BANK_DETAILS = /*$$(*/
|
||||
"Company bank details is missing in batch." /*)*/;
|
||||
static final String BATCH_DIRECT_DEBIT_NO_PROCESSED_PAYMENT_SCHEDULE_LINES = /*$$(*/
|
||||
"No processed payment schedule lines" /*)*/;
|
||||
static final String BATCH_DIRECT_DEBIT_UNKNOWN_DATA_TYPE = /*$$(*/
|
||||
"Unknown direct debit data type" /*)*/;
|
||||
static final String DIRECT_DEBIT_MISSING_PARTNER_ACTIVE_UMR = /*$$(*/
|
||||
"Please add an Active UMR to the partner." /*)*/;
|
||||
|
||||
/** Generate bank order from invoices */
|
||||
static final String INVOICE_BANK_ORDER_ALREADY_EXIST = /*$$(*/
|
||||
"A bank order %s already exist for the invoice %s." /*)*/;
|
||||
|
||||
static final String MOVE_LINE_ARCHIVE_NOT_OK_BECAUSE_OF_BANK_RECONCILIATION_AMOUNT = /*$$(*/
|
||||
"This move line %s can not be archived because its bank reconciliation amount is superior to 0." /*)*/;
|
||||
}
|
||||
@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.module;
|
||||
|
||||
import com.axelor.app.AxelorModule;
|
||||
import com.axelor.apps.account.db.repo.MoveManagementRepository;
|
||||
import com.axelor.apps.account.service.AccountingReportServiceImpl;
|
||||
import com.axelor.apps.account.service.PaymentScheduleLineServiceImpl;
|
||||
import com.axelor.apps.account.service.batch.AccountingBatchService;
|
||||
import com.axelor.apps.account.service.batch.BatchCreditTransferPartnerReimbursement;
|
||||
import com.axelor.apps.account.service.batch.BatchCreditTransferSupplierPayment;
|
||||
import com.axelor.apps.account.service.extract.ExtractContextMoveServiceImpl;
|
||||
import com.axelor.apps.account.service.move.MoveRemoveService;
|
||||
import com.axelor.apps.account.service.move.MoveServiceImpl;
|
||||
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCancelServiceImpl;
|
||||
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateServiceImpl;
|
||||
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentValidateServiceImpl;
|
||||
import com.axelor.apps.account.web.InvoicePaymentController;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderLineManagementRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderLineRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderManagementRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankReconciliationManagementRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankReconciliationRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsBankAccountRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsBankRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsCertificateAccountRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsCertificateRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsUserManagementRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsUserRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.MoveBankPaymentRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsBankService;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsBankServiceImpl;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsPartnerService;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsPartnerServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.AccountingReportBankPaymentService;
|
||||
import com.axelor.apps.bankpayment.service.AccountingReportBankPaymentServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.PaymentScheduleLineBankPaymentService;
|
||||
import com.axelor.apps.bankpayment.service.PaymentScheduleLineBankPaymentServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.app.AppBankPaymentService;
|
||||
import com.axelor.apps.bankpayment.service.app.AppBankPaymentServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderLineOriginService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderLineOriginServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderMergeService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderMergeServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderMoveService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderMoveServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.BankOrderServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.batch.AccountingBatchBankPaymentService;
|
||||
import com.axelor.apps.bankpayment.service.batch.BatchBankPaymentService;
|
||||
import com.axelor.apps.bankpayment.service.batch.BatchBankPaymentServiceImpl;
|
||||
import com.axelor.apps.bankpayment.service.batch.BatchCreditTransferPartnerReimbursementBankPayment;
|
||||
import com.axelor.apps.bankpayment.service.batch.BatchCreditTransferSupplierPaymentBankPayment;
|
||||
import com.axelor.apps.bankpayment.service.extract.ExtractContextMoveServiceBankPaymentImpl;
|
||||
import com.axelor.apps.bankpayment.service.invoice.payment.InvoicePaymentCancelServiceBankPayImpl;
|
||||
import com.axelor.apps.bankpayment.service.invoice.payment.InvoicePaymentCreateServiceBankPay;
|
||||
import com.axelor.apps.bankpayment.service.invoice.payment.InvoicePaymentCreateServiceBankPayImpl;
|
||||
import com.axelor.apps.bankpayment.service.invoice.payment.InvoicePaymentValidateServiceBankPayImpl;
|
||||
import com.axelor.apps.bankpayment.service.move.MoveRemoveServiceBankPaymentImpl;
|
||||
import com.axelor.apps.bankpayment.service.move.MoveServiceBankPaymentImpl;
|
||||
import com.axelor.apps.bankpayment.web.InvoicePaymentBankPayController;
|
||||
|
||||
public class BankPaymentModule extends AxelorModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
|
||||
bind(AppBankPaymentService.class).to(AppBankPaymentServiceImpl.class);
|
||||
|
||||
bind(BankReconciliationRepository.class).to(BankReconciliationManagementRepository.class);
|
||||
|
||||
bind(BankOrderRepository.class).to(BankOrderManagementRepository.class);
|
||||
|
||||
bind(BankOrderLineRepository.class).to(BankOrderLineManagementRepository.class);
|
||||
|
||||
bind(EbicsBankRepository.class).to(EbicsBankAccountRepository.class);
|
||||
|
||||
bind(EbicsBankService.class).to(EbicsBankServiceImpl.class);
|
||||
|
||||
bind(EbicsPartnerService.class).to(EbicsPartnerServiceImpl.class);
|
||||
|
||||
bind(EbicsCertificateRepository.class).to(EbicsCertificateAccountRepository.class);
|
||||
|
||||
bind(BankOrderService.class).to(BankOrderServiceImpl.class);
|
||||
|
||||
bind(BankOrderMergeService.class).to(BankOrderMergeServiceImpl.class);
|
||||
|
||||
bind(BankOrderMoveService.class).to(BankOrderMoveServiceImpl.class);
|
||||
|
||||
bind(InvoicePaymentCancelServiceImpl.class).to(InvoicePaymentCancelServiceBankPayImpl.class);
|
||||
|
||||
bind(InvoicePaymentValidateServiceImpl.class)
|
||||
.to(InvoicePaymentValidateServiceBankPayImpl.class);
|
||||
|
||||
bind(BatchCreditTransferSupplierPayment.class)
|
||||
.to(BatchCreditTransferSupplierPaymentBankPayment.class);
|
||||
|
||||
bind(BatchCreditTransferPartnerReimbursement.class)
|
||||
.to(BatchCreditTransferPartnerReimbursementBankPayment.class);
|
||||
|
||||
bind(AccountingBatchService.class).to(AccountingBatchBankPaymentService.class);
|
||||
|
||||
bind(BatchBankPaymentService.class).to(BatchBankPaymentServiceImpl.class);
|
||||
|
||||
bind(PaymentScheduleLineServiceImpl.class).to(PaymentScheduleLineBankPaymentServiceImpl.class);
|
||||
bind(PaymentScheduleLineBankPaymentService.class)
|
||||
.to(PaymentScheduleLineBankPaymentServiceImpl.class);
|
||||
|
||||
bind(InvoicePaymentCreateServiceBankPay.class).to(InvoicePaymentCreateServiceBankPayImpl.class);
|
||||
|
||||
bind(InvoicePaymentCreateServiceImpl.class).to(InvoicePaymentCreateServiceBankPayImpl.class);
|
||||
|
||||
bind(InvoicePaymentController.class).to(InvoicePaymentBankPayController.class);
|
||||
|
||||
bind(MoveManagementRepository.class).to(MoveBankPaymentRepository.class);
|
||||
|
||||
bind(BankOrderLineOriginService.class).to(BankOrderLineOriginServiceImpl.class);
|
||||
|
||||
bind(MoveServiceImpl.class).to(MoveServiceBankPaymentImpl.class);
|
||||
|
||||
bind(ExtractContextMoveServiceImpl.class).to(ExtractContextMoveServiceBankPaymentImpl.class);
|
||||
|
||||
bind(MoveRemoveService.class).to(MoveRemoveServiceBankPaymentImpl.class);
|
||||
|
||||
bind(EbicsUserRepository.class).to(EbicsUserManagementRepository.class);
|
||||
|
||||
bind(AccountingReportBankPaymentService.class).to(AccountingReportBankPaymentServiceImpl.class);
|
||||
bind(AccountingReportServiceImpl.class).to(AccountingReportBankPaymentServiceImpl.class);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.report;
|
||||
|
||||
public interface IReport {
|
||||
|
||||
public static final String BANK_ORDER = "BankOrder.rptdesign";
|
||||
public static final String EBICS_CERTIFICATE = "EbicsCertificate.rptdesign";
|
||||
public static final String BANK_STATEMENT_AFB120 = "BankStatementAFB120.rptdesign";
|
||||
public static final String BANK_RECONCILIATION = "BankReconciliation.rptdesign";
|
||||
public static final String BANK_PAYMENT_REPORT_TYPE = "BankReconciliationStatement.rptdesign";
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.report;
|
||||
|
||||
public interface ITranslation {
|
||||
|
||||
public static final String EBICS_CERTIFICATE_SIGNATURE_TITLE = /*$$(*/
|
||||
"EbicsCertificateReport.signatureTitle"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_AUTHENTICATION_TITLE = /*$$(*/
|
||||
"EbicsCertificateReport.authenticationTitle"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_ENCRYPTION_TITLE = /*$$(*/
|
||||
"EbicsCertificateReport.encryptionTitle"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_SIGNATURE = /*$$(*/
|
||||
"EbicsCertificateReport.signature"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_AUTHENTICATION = /*$$(*/
|
||||
"EbicsCertificateReport.authentication"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_ENCRYPTION = /*$$(*/
|
||||
"EbicsCertificateReport.encryption"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_SIGNATURE_HASH = /*$$(*/
|
||||
"EbicsCertificateReport.signatureHash"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_AUTHENTICATION_HASH = /*$$(*/
|
||||
"EbicsCertificateReport.authenticationHash"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_ENCRYPTION_HASH = /*$$(*/
|
||||
"EbicsCertificateReport.encryptionHash"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_ISSUED_TO = /*$$(*/
|
||||
"EbicsCertificateReport.issuedTo"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_ISSUED_BY = /*$$(*/
|
||||
"EbicsCertificateReport.issuedBy"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_BANK = /*$$(*/ "EbicsCertificateReport.bank"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_SIGNATURE_VERSION = /*$$(*/
|
||||
"EbicsCertificateReport.signatureVersion"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_AUTHENTICATION_VERSION = /*$$(*/
|
||||
"EbicsCertificateReport.authenticationVersion"; /*)*/
|
||||
public static final String EBICS_CERTIFICATE_ENCRYPTION_VERSION = /*$$(*/
|
||||
"EbicsCertificateReport.encryptionVersion"; /*)*/
|
||||
|
||||
public static final String BANK_STATEMENT_TITLE = /*$$(*/ "BankStatement.title"; /*)*/;
|
||||
public static final String BANK_STATEMENT_CREATION_DATE_FROM = /*$$(*/
|
||||
"BankStatement.creationDateFrom"; /*)*/;
|
||||
public static final String BANK_STATEMENT_CREATION_DATE_TO = /*$$(*/
|
||||
"BankStatement.creationDateTo"; /*)*/;
|
||||
public static final String BANK_STATEMENT_HEADER_TEXT = /*$$(*/ "BankStatement.headerText"; /*)*/;
|
||||
public static final String BANK_STATEMENT_OPERATION_DATE = /*$$(*/
|
||||
"BankStatement.operationDate"; /*)*/;
|
||||
public static final String BANK_STATEMENT_VALUE_DATE = /*$$(*/ "BankStatement.valueDate"; /*)*/;
|
||||
public static final String BANK_STATEMENT_LABEL = /*$$(*/ "BankStatement.label"; /*)*/;
|
||||
public static final String BANK_STATEMENT_REFERENCE = /*$$(*/ "BankStatement.reference"; /*)*/;
|
||||
public static final String BANK_STATEMENT_EXEMPT = /*$$(*/ "BankStatement.exempt"; /*)*/;
|
||||
public static final String BANK_STATEMENT_UNAVAILABLE = /*$$(*/
|
||||
"BankStatement.unavailable"; /*)*/;
|
||||
public static final String BANK_STATEMENT_ORIGIN = /*$$(*/ "BankStatement.origin"; /*)*/;
|
||||
public static final String BANK_STATEMENT_DEBIT = /*$$(*/ "BankStatement.debit"; /*)*/;
|
||||
public static final String BANK_STATEMENT_CREDIT = /*$$(*/ "BankStatement.credit"; /*)*/;
|
||||
public static final String BANK_STATEMENT_YES = /*$$(*/ "BankStatement.yes"; /*)*/
|
||||
public static final String BANK_STATEMENT_INITIAL_BALANCE = /*$$(*/
|
||||
"BankStatement.initialBalance"; /*)*/;
|
||||
public static final String BANK_STATEMENT_MOVEMENT = /*$$(*/ "BankStatement.movement"; /*)*/;
|
||||
public static final String BANK_STATEMENT_FINAL_BALANCE = /*$$(*/
|
||||
"BankStatement.finalBalance"; /*)*/;
|
||||
public static final String BANK_STATEMENT_TOTAL_OF_OPERATIONS = /*$$(*/
|
||||
"BankStatement.totalOfOperations"; /*)*/;
|
||||
public static final String BANK_STATEMENT_BANK_ACCOUNT = /*$$(*/
|
||||
"BankStatement.bankAccount"; /*)*/;
|
||||
public static final String BANK_STATEMENT_IBAN = /*$$(*/ "BankStatement.iban"; /*)*/;
|
||||
public static final String BANK_STATEMENT_ACCOUNT_CURRENCY = /*$$(*/
|
||||
"BankStatement.accountCurrency"; /*)*/;
|
||||
|
||||
public static final String BANK_RECONCILIATION_REPORT_EDITION_DATE = /*$$(*/
|
||||
"BankReconciliation.report_edition_date"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_PAGE1_TITLE = /*$$(*/
|
||||
"BankReconciliation.page1Title"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_PAGE2_TITLE = /*$$(*/
|
||||
"BankReconciliation.page2Title"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_ACOUNT = /*$$(*/
|
||||
"BankReconciliation.account"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_JOURNAL = /*$$(*/
|
||||
"BankReconciliation.journal"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_CURRENCY = /*$$(*/
|
||||
"BankReconciliation.currency"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_COMPANY = /*$$(*/
|
||||
"BankReconciliation.company"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_REPORT_DATE = /*$$(*/
|
||||
"BankReconciliation.report_date"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_CASH_ACCOUNT = /*$$(*/
|
||||
"BankReconciliation.cash_account"; /*)*/;
|
||||
|
||||
public static final String BANK_RECONCILIATION_TYPE = /*$$(*/ "BankReconciliation.type"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_CODE = /*$$(*/ "BankReconciliation.code"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_TO_DATE = /*$$(*/
|
||||
"BankReconciliation.to_date"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_REFERENCE = /*$$(*/
|
||||
"BankReconciliation.reference"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_NAME = /*$$(*/ "BankReconciliation.name"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_DEBIT = /*$$(*/ "BankReconciliation.debit"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_CREDIT = /*$$(*/
|
||||
"BankReconciliation.credit"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_AMOUNT = /*$$(*/
|
||||
"BankReconciliation.amount"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_UNRECONCILED_MOVE_LINES = /*$$(*/
|
||||
"BankReconciliation.unreconciled_move_lines"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_MOVES_UNACCOUNTED = /*$$(*/
|
||||
"BankReconciliation.moves_unaccounted"; /*)*/;
|
||||
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_COMPANY = /*$$(*/
|
||||
"BankReconciliationStatement.company"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_CURRENCY = /*$$(*/
|
||||
"BankReconciliationStatement.currency"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_JOURNAL = /*$$(*/
|
||||
"BankReconciliationStatement.journal"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_DATE = /*$$(*/
|
||||
"BankReconciliationStatement.date"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_PAGE1TITLE = /*$$(*/
|
||||
"BankReconciliationStatement.page1Title"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_PAGE2TITLE = /*$$(*/
|
||||
"BankReconciliationStatement.page2Title"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_CODE = /*$$(*/
|
||||
"BankReconciliationStatement.code"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_REFERENCE = /*$$(*/
|
||||
"BankReconciliationStatement.reference"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_DESCRIPTION = /*$$(*/
|
||||
"BankReconciliationStatement.description"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_DEBIT = /*$$(*/
|
||||
"BankReconciliationStatement.debit"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_CREDIT = /*$$(*/
|
||||
"BankReconciliationStatement.credit"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_AMOUNT_REMAINING = /*$$(*/
|
||||
"BankReconciliationStatement.amountRemaining"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_NAME = /*$$(*/
|
||||
"BankReconciliationStatement.name"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_ACCOUNT_CODE = /*$$(*/
|
||||
"BankReconciliationStatement.accountCode"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_JOURNAL_CODE = /*$$(*/
|
||||
"BankReconciliationStatement.journalCode"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_LINE = /*$$(*/
|
||||
"BankReconciliationStatement.line"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_AMOUNT_TO_RECONCILE = /*$$(*/
|
||||
"BankReconciliationStatement.amountToReconcile"; /*)*/;
|
||||
public static final String BANK_RECONCILIATION_STATEMENT_NO_LINE_FOUND_MESSAGE = /*$$(*/
|
||||
"BankReconciliationStatement.noLineFoundMessage"; /*)*/;
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service;
|
||||
|
||||
import com.axelor.apps.account.db.AccountingReport;
|
||||
|
||||
public interface AccountingReportBankPaymentService {
|
||||
|
||||
public String createDomainForBankDetails(AccountingReport accountingReport);
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service;
|
||||
|
||||
import com.axelor.apps.ReportFactory;
|
||||
import com.axelor.apps.account.db.AccountingReport;
|
||||
import com.axelor.apps.account.db.repo.AccountRepository;
|
||||
import com.axelor.apps.account.db.repo.AccountingReportRepository;
|
||||
import com.axelor.apps.account.exception.IExceptionMessage;
|
||||
import com.axelor.apps.account.service.AccountingReportServiceImpl;
|
||||
import com.axelor.apps.account.service.app.AppAccountService;
|
||||
import com.axelor.apps.bankpayment.report.IReport;
|
||||
import com.axelor.apps.base.db.repo.SequenceRepository;
|
||||
import com.axelor.apps.base.service.BankDetailsService;
|
||||
import com.axelor.apps.base.service.administration.SequenceService;
|
||||
import com.axelor.apps.report.engine.ReportSettings;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class AccountingReportBankPaymentServiceImpl extends AccountingReportServiceImpl
|
||||
implements AccountingReportBankPaymentService {
|
||||
|
||||
@Inject
|
||||
public AccountingReportBankPaymentServiceImpl(
|
||||
AppAccountService appBaseService,
|
||||
AccountingReportRepository accountingReportRepo,
|
||||
AccountRepository accountRepo) {
|
||||
super(appBaseService, accountingReportRepo, accountRepo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createDomainForBankDetails(AccountingReport accountingReport) {
|
||||
return Beans.get(BankDetailsService.class)
|
||||
.getActiveCompanyBankDetails(accountingReport.getCompany(), accountingReport.getCurrency());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReportFileLink(AccountingReport accountingReport, String name)
|
||||
throws AxelorException {
|
||||
if (accountingReport.getTypeSelect()
|
||||
>= AccountingReportRepository.REPORT_BANK_RECONCILIATION_STATEMENT) {
|
||||
return ReportFactory.createReport(IReport.BANK_PAYMENT_REPORT_TYPE, name + "-${date}")
|
||||
.addParam("AccountingReportId", accountingReport.getId())
|
||||
.addParam("Locale", ReportSettings.getPrintingLocale(null))
|
||||
.addFormat(accountingReport.getExportTypeSelect())
|
||||
.toAttach(accountingReport)
|
||||
.generate()
|
||||
.getFileLink();
|
||||
} else {
|
||||
return super.getReportFileLink(accountingReport, name);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSequence(AccountingReport accountingReport) throws AxelorException {
|
||||
SequenceService sequenceService = Beans.get(SequenceService.class);
|
||||
int accountingReportTypeSelect = accountingReport.getTypeSelect();
|
||||
|
||||
if (accountingReportTypeSelect >= 3000) {
|
||||
String seq =
|
||||
sequenceService.getSequenceNumber(
|
||||
SequenceRepository.ACCOUNTING_REPORT, accountingReport.getCompany());
|
||||
if (seq == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.ACCOUNTING_REPORT_1),
|
||||
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
|
||||
accountingReport.getCompany().getName());
|
||||
}
|
||||
return seq;
|
||||
} else {
|
||||
return super.getSequence(accountingReport);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service;
|
||||
|
||||
import com.axelor.apps.account.db.InterbankCodeLine;
|
||||
import com.axelor.apps.account.db.PaymentScheduleLine;
|
||||
import com.axelor.apps.account.service.PaymentScheduleLineService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.meta.CallMethod;
|
||||
import java.util.Map;
|
||||
|
||||
public interface PaymentScheduleLineBankPaymentService extends PaymentScheduleLineService {
|
||||
/**
|
||||
* Reject a payment schedule line.
|
||||
*
|
||||
* @param paymentScheduleLine
|
||||
* @param rejectionReason
|
||||
* @param represent
|
||||
* @throws AxelorException
|
||||
*/
|
||||
void reject(
|
||||
PaymentScheduleLine paymentScheduleLine, InterbankCodeLine rejectionReason, boolean represent)
|
||||
throws AxelorException;
|
||||
|
||||
/**
|
||||
* Reject a payment schedule line.
|
||||
*
|
||||
* @param name
|
||||
* @param rejectionReason
|
||||
* @param represent
|
||||
* @throws AxelorException
|
||||
*/
|
||||
void reject(String name, InterbankCodeLine rejectionReason, boolean represent)
|
||||
throws AxelorException;
|
||||
|
||||
/**
|
||||
* Reject payment schedule line from ID.
|
||||
*
|
||||
* @param id
|
||||
* @param rejectionReason
|
||||
* @param represent
|
||||
* @throws AxelorException
|
||||
*/
|
||||
void reject(long id, InterbankCodeLine rejectionReason, boolean represent) throws AxelorException;
|
||||
|
||||
/**
|
||||
* Reject payment schedule line from a map of IDs.
|
||||
*
|
||||
* @param idMap
|
||||
* @param represent
|
||||
* @return
|
||||
*/
|
||||
int rejectFromIdMap(Map<Long, InterbankCodeLine> idMap, boolean represent);
|
||||
|
||||
/**
|
||||
* Reject payment schedule line from a map of names.
|
||||
*
|
||||
* @param nameMap
|
||||
* @param represent
|
||||
* @return
|
||||
*/
|
||||
int rejectFromNameMap(Map<String, InterbankCodeLine> nameMap, boolean represent);
|
||||
|
||||
/**
|
||||
* Get default rejection reason.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@CallMethod
|
||||
InterbankCodeLine getDefaultRejectionReason();
|
||||
}
|
||||
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service;
|
||||
|
||||
import com.axelor.apps.account.db.InterbankCodeLine;
|
||||
import com.axelor.apps.account.db.Invoice;
|
||||
import com.axelor.apps.account.db.InvoicePayment;
|
||||
import com.axelor.apps.account.db.Move;
|
||||
import com.axelor.apps.account.db.MoveLine;
|
||||
import com.axelor.apps.account.db.PaymentSchedule;
|
||||
import com.axelor.apps.account.db.PaymentScheduleLine;
|
||||
import com.axelor.apps.account.db.Reconcile;
|
||||
import com.axelor.apps.account.db.repo.InterbankCodeLineRepository;
|
||||
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
|
||||
import com.axelor.apps.account.db.repo.MoveLineRepository;
|
||||
import com.axelor.apps.account.db.repo.PaymentScheduleLineRepository;
|
||||
import com.axelor.apps.account.db.repo.PaymentScheduleRepository;
|
||||
import com.axelor.apps.account.db.repo.ReconcileRepository;
|
||||
import com.axelor.apps.account.service.AccountingSituationService;
|
||||
import com.axelor.apps.account.service.PaymentScheduleLineServiceImpl;
|
||||
import com.axelor.apps.account.service.PaymentScheduleService;
|
||||
import com.axelor.apps.account.service.move.MoveLineService;
|
||||
import com.axelor.apps.account.service.move.MoveService;
|
||||
import com.axelor.apps.account.service.move.MoveToolService;
|
||||
import com.axelor.apps.account.service.move.MoveValidateService;
|
||||
import com.axelor.apps.account.service.payment.PaymentModeService;
|
||||
import com.axelor.apps.account.service.payment.PaymentService;
|
||||
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCancelService;
|
||||
import com.axelor.apps.base.service.administration.SequenceService;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.exception.service.TraceBackService;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PaymentScheduleLineBankPaymentServiceImpl extends PaymentScheduleLineServiceImpl
|
||||
implements PaymentScheduleLineBankPaymentService {
|
||||
|
||||
protected InvoicePaymentCancelService invoicePaymentCancelService;
|
||||
protected InterbankCodeLineRepository interbankCodeLineRepo;
|
||||
protected ReconcileRepository reconcileRepo;
|
||||
protected InvoicePaymentRepository invoicePaymentRepo;
|
||||
|
||||
@Inject
|
||||
public PaymentScheduleLineBankPaymentServiceImpl(
|
||||
AppBaseService appBaseService,
|
||||
PaymentScheduleService paymentScheduleService,
|
||||
MoveService moveService,
|
||||
PaymentModeService paymentModeService,
|
||||
SequenceService sequenceService,
|
||||
AccountingSituationService accountingSituationService,
|
||||
MoveToolService moveToolService,
|
||||
PaymentService paymentService,
|
||||
InvoicePaymentCancelService invoicePaymentCancelService,
|
||||
InterbankCodeLineRepository interbankCodeLineRepo,
|
||||
MoveLineRepository moveLineRepo,
|
||||
PaymentScheduleLineRepository paymentScheduleLineRepo,
|
||||
ReconcileRepository reconcileRepo,
|
||||
InvoicePaymentRepository invoicePaymentRepo) {
|
||||
super(
|
||||
appBaseService,
|
||||
paymentScheduleService,
|
||||
moveService,
|
||||
paymentModeService,
|
||||
sequenceService,
|
||||
accountingSituationService,
|
||||
moveToolService,
|
||||
paymentService,
|
||||
moveLineRepo,
|
||||
paymentScheduleLineRepo);
|
||||
this.invoicePaymentCancelService = invoicePaymentCancelService;
|
||||
this.interbankCodeLineRepo = interbankCodeLineRepo;
|
||||
this.reconcileRepo = reconcileRepo;
|
||||
this.invoicePaymentRepo = invoicePaymentRepo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void reject(
|
||||
PaymentScheduleLine paymentScheduleLine, InterbankCodeLine rejectionReason, boolean represent)
|
||||
throws AxelorException {
|
||||
Preconditions.checkNotNull(
|
||||
paymentScheduleLine, I18n.get("Payment schedule line cannot be null."));
|
||||
PaymentSchedule paymentSchedule = paymentScheduleLine.getPaymentSchedule();
|
||||
Preconditions.checkNotNull(
|
||||
paymentSchedule, I18n.get("Parent payment schedule cannot be null."));
|
||||
|
||||
if (paymentScheduleLine.getStatusSelect() != PaymentScheduleLineRepository.STATUS_VALIDATED) {
|
||||
throw new AxelorException(
|
||||
paymentScheduleLine,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get("Only validated payment schedule lines can be rejected."));
|
||||
}
|
||||
|
||||
Move rejectionMove = createRejectionMove(paymentScheduleLine);
|
||||
|
||||
if (paymentSchedule.getTypeSelect() == PaymentScheduleRepository.TYPE_TERMS) {
|
||||
cancelInvoicePayments(paymentScheduleLine);
|
||||
}
|
||||
|
||||
if (represent) {
|
||||
representPaymentScheduleLine(paymentScheduleLine);
|
||||
}
|
||||
|
||||
if (rejectionReason == null) {
|
||||
rejectionReason = getDefaultRejectionReason();
|
||||
}
|
||||
|
||||
MoveLine rejectionMoveLine =
|
||||
moveService.findMoveLineByAccount(
|
||||
rejectionMove, paymentScheduleLine.getAdvanceMoveLine().getAccount());
|
||||
|
||||
paymentScheduleLine.setInterbankCodeLine(rejectionReason);
|
||||
paymentScheduleLine.setRejectMoveLine(rejectionMoveLine);
|
||||
paymentScheduleLine.setRejectDate(rejectionMove.getDate());
|
||||
paymentScheduleLine.setAmountRejected(paymentScheduleLine.getRejectMoveLine().getDebit());
|
||||
paymentScheduleLine.setRejectedOk(true);
|
||||
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_CLOSED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reject(
|
||||
String paymentScheduleLineName, InterbankCodeLine rejectionReason, boolean represent)
|
||||
throws AxelorException {
|
||||
PaymentScheduleLine paymentScheduleLine =
|
||||
paymentScheduleLineRepo.findByName(paymentScheduleLineName);
|
||||
reject(paymentScheduleLine, rejectionReason, represent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InterbankCodeLine getDefaultRejectionReason() {
|
||||
return interbankCodeLineRepo.findByCode("A3");
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
protected Move createRejectionMove(PaymentScheduleLine paymentScheduleLine)
|
||||
throws AxelorException {
|
||||
MoveValidateService moveValidateService = moveService.getMoveValidateService();
|
||||
MoveLineService moveLineService = moveService.getMoveLineService();
|
||||
|
||||
Move advanceOrPaymentMove = paymentScheduleLine.getAdvanceOrPaymentMove();
|
||||
Move rejectionMove =
|
||||
moveService.generateReverse(
|
||||
advanceOrPaymentMove, true, true, false, advanceOrPaymentMove.getDate());
|
||||
rejectionMove.setRejectOk(true);
|
||||
moveValidateService.validate(rejectionMove);
|
||||
|
||||
List<MoveLine> moveLineList = new ArrayList<>();
|
||||
moveLineList.addAll(advanceOrPaymentMove.getMoveLineList());
|
||||
moveLineList.addAll(rejectionMove.getMoveLineList());
|
||||
moveLineService.reconcileMoveLines(moveLineList);
|
||||
|
||||
return rejectionMove;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
protected void cancelInvoicePayments(PaymentScheduleLine paymentScheduleLine)
|
||||
throws AxelorException {
|
||||
MoveLineService moveLineService = moveService.getMoveLineService();
|
||||
PaymentSchedule paymentSchedule = paymentScheduleLine.getPaymentSchedule();
|
||||
MoveLine creditMoveLine = paymentScheduleLine.getAdvanceMoveLine();
|
||||
Set<Invoice> invoiceSet =
|
||||
MoreObjects.firstNonNull(paymentSchedule.getInvoiceSet(), Collections.emptySet());
|
||||
|
||||
for (Invoice invoice : invoiceSet) {
|
||||
MoveLine debitMoveLine = moveLineService.getDebitCustomerMoveLine(invoice);
|
||||
Reconcile reconcile = reconcileRepo.findByMoveLines(debitMoveLine, creditMoveLine);
|
||||
|
||||
if (reconcile == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (InvoicePayment invoicePayment : invoicePaymentRepo.findByReconcile(reconcile).fetch()) {
|
||||
invoicePaymentCancelService.cancel(invoicePayment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
protected PaymentScheduleLine representPaymentScheduleLine(
|
||||
PaymentScheduleLine paymentScheduleLine) {
|
||||
PaymentSchedule paymentSchedule = paymentScheduleLine.getPaymentSchedule();
|
||||
BigDecimal inTaxAmount = paymentScheduleLine.getInTaxAmount();
|
||||
int scheduleLineSeq = paymentScheduleService.getNextScheduleLineSeq(paymentSchedule);
|
||||
LocalDate scheduleDate = paymentScheduleLine.getScheduleDate();
|
||||
PaymentScheduleLine representedPaymentScheduleLine =
|
||||
createPaymentScheduleLine(paymentSchedule, inTaxAmount, scheduleLineSeq, scheduleDate);
|
||||
representedPaymentScheduleLine.setFromReject(true);
|
||||
representedPaymentScheduleLine.setStatusSelect(
|
||||
PaymentScheduleLineRepository.STATUS_IN_PROGRESS);
|
||||
return representedPaymentScheduleLine;
|
||||
}
|
||||
|
||||
protected void refindPaymentScheduleLines(
|
||||
List<PaymentScheduleLine> paymentScheduleLines, int index) {
|
||||
List<Long> idList =
|
||||
paymentScheduleLines
|
||||
.subList(Math.max(index, paymentScheduleLines.size()), paymentScheduleLines.size())
|
||||
.stream()
|
||||
.map(PaymentScheduleLine::getId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!idList.isEmpty()) {
|
||||
List<PaymentScheduleLine> foundPaymentScheduleLines =
|
||||
paymentScheduleLineRepo.findByIdList(idList).fetch();
|
||||
|
||||
if (foundPaymentScheduleLines.size() != idList.size()) {
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
"Expected size: %d, got: %d", idList.size(), foundPaymentScheduleLines.size()));
|
||||
}
|
||||
|
||||
for (int i = 0; i < foundPaymentScheduleLines.size(); ++i) {
|
||||
paymentScheduleLines.set(index + i, foundPaymentScheduleLines.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reject(long id, InterbankCodeLine rejectionReason, boolean represent)
|
||||
throws AxelorException {
|
||||
PaymentScheduleLine paymentScheduleLine = paymentScheduleLineRepo.find(id);
|
||||
reject(paymentScheduleLine, rejectionReason, represent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int rejectFromIdMap(Map<Long, InterbankCodeLine> idMap, boolean represent) {
|
||||
return rejectFromMap(idMap, represent, paymentScheduleLineRepo::find);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int rejectFromNameMap(Map<String, InterbankCodeLine> nameMap, boolean represent) {
|
||||
return rejectFromMap(nameMap, represent, paymentScheduleLineRepo::findByName);
|
||||
}
|
||||
|
||||
protected <T> int rejectFromMap(
|
||||
Map<T, InterbankCodeLine> map, boolean represent, Function<T, PaymentScheduleLine> findFunc) {
|
||||
|
||||
int errorCount = 0;
|
||||
|
||||
for (Entry<T, InterbankCodeLine> entry : map.entrySet()) {
|
||||
T key = entry.getKey();
|
||||
InterbankCodeLine rejectionReason = entry.getValue();
|
||||
PaymentScheduleLine paymentScheduleLine = findFunc.apply(key);
|
||||
|
||||
try {
|
||||
reject(paymentScheduleLine, rejectionReason, represent);
|
||||
} catch (Exception e) {
|
||||
TraceBackService.trace(e);
|
||||
++errorCount;
|
||||
}
|
||||
}
|
||||
|
||||
return errorCount;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.app;
|
||||
|
||||
import com.axelor.apps.base.db.AppBankPayment;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
|
||||
public interface AppBankPaymentService extends AppBaseService {
|
||||
|
||||
public AppBankPayment getAppBankPayment();
|
||||
|
||||
public void generateBankPaymentConfigurations();
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.app;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankPaymentConfig;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankPaymentConfigRepository;
|
||||
import com.axelor.apps.base.db.AppBankPayment;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.repo.AppBankPaymentRepository;
|
||||
import com.axelor.apps.base.db.repo.CompanyRepository;
|
||||
import com.axelor.apps.base.service.app.AppBaseServiceImpl;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.List;
|
||||
|
||||
@Singleton
|
||||
public class AppBankPaymentServiceImpl extends AppBaseServiceImpl implements AppBankPaymentService {
|
||||
|
||||
protected AppBankPaymentRepository appBankPaymentRepo;
|
||||
protected BankPaymentConfigRepository bankPaymentConfigRepo;
|
||||
protected CompanyRepository companyRepo;
|
||||
|
||||
@Inject
|
||||
AppBankPaymentServiceImpl(
|
||||
AppBankPaymentRepository appBankPaymentRepo,
|
||||
BankPaymentConfigRepository bankPaymentConfigRepo,
|
||||
CompanyRepository companyRepo) {
|
||||
this.appBankPaymentRepo = appBankPaymentRepo;
|
||||
this.bankPaymentConfigRepo = bankPaymentConfigRepo;
|
||||
this.companyRepo = companyRepo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AppBankPayment getAppBankPayment() {
|
||||
return appBankPaymentRepo.all().fetchOne();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void generateBankPaymentConfigurations() {
|
||||
List<Company> companies = companyRepo.all().filter("self.bankPaymentConfig IS NULL").fetch();
|
||||
|
||||
for (Company company : companies) {
|
||||
BankPaymentConfig config = new BankPaymentConfig();
|
||||
config.setCompany(company);
|
||||
bankPaymentConfigRepo.save(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder;
|
||||
|
||||
import com.axelor.apps.account.db.Invoice;
|
||||
import com.axelor.apps.account.db.InvoicePayment;
|
||||
import com.axelor.apps.account.db.PaymentMode;
|
||||
import com.axelor.apps.account.db.repo.InvoiceRepository;
|
||||
import com.axelor.apps.account.service.invoice.InvoiceService;
|
||||
import com.axelor.apps.account.service.invoice.InvoiceToolService;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderFileFormat;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderRepository;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Currency;
|
||||
import com.axelor.apps.base.db.Partner;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BankOrderCreateService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
protected BankOrderRepository bankOrderRepo;
|
||||
protected BankOrderService bankOrderService;
|
||||
protected BankOrderLineService bankOrderLineService;
|
||||
protected InvoiceService invoiceService;
|
||||
|
||||
@Inject
|
||||
public BankOrderCreateService(
|
||||
BankOrderRepository bankOrderRepo,
|
||||
BankOrderService bankOrderService,
|
||||
BankOrderLineService bankOrderLineService,
|
||||
InvoiceService invoiceService) {
|
||||
|
||||
this.bankOrderRepo = bankOrderRepo;
|
||||
this.bankOrderService = bankOrderService;
|
||||
this.bankOrderLineService = bankOrderLineService;
|
||||
this.invoiceService = invoiceService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Créer un ordre bancaire avec tous les paramètres
|
||||
*
|
||||
* @param
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public BankOrder createBankOrder(
|
||||
PaymentMode paymentMode,
|
||||
Integer partnerType,
|
||||
LocalDate bankOrderDate,
|
||||
Company senderCompany,
|
||||
BankDetails senderBankDetails,
|
||||
Currency currency,
|
||||
String senderReference,
|
||||
String senderLabel,
|
||||
int technicalOriginSelect)
|
||||
throws AxelorException {
|
||||
|
||||
BankOrderFileFormat bankOrderFileFormat = paymentMode.getBankOrderFileFormat();
|
||||
|
||||
BankOrder bankOrder = new BankOrder();
|
||||
|
||||
bankOrder.setOrderTypeSelect(paymentMode.getOrderTypeSelect());
|
||||
bankOrder.setPaymentMode(paymentMode);
|
||||
bankOrder.setPartnerTypeSelect(partnerType);
|
||||
|
||||
if (!bankOrderFileFormat.getIsMultiDate()) {
|
||||
bankOrder.setBankOrderDate(bankOrderDate);
|
||||
}
|
||||
|
||||
bankOrder.setStatusSelect(BankOrderRepository.STATUS_DRAFT);
|
||||
bankOrder.setRejectStatusSelect(BankOrderRepository.REJECT_STATUS_NOT_REJECTED);
|
||||
bankOrder.setSenderCompany(senderCompany);
|
||||
bankOrder.setSenderBankDetails(senderBankDetails);
|
||||
EbicsUser signatoryEbicsUser =
|
||||
bankOrderService.getDefaultEbicsUserFromBankDetails(senderBankDetails);
|
||||
User signatoryUser = null;
|
||||
if (signatoryEbicsUser != null) {
|
||||
signatoryUser = signatoryEbicsUser.getAssociatedUser();
|
||||
bankOrder.setSignatoryEbicsUser(signatoryEbicsUser);
|
||||
}
|
||||
if (signatoryUser != null) {
|
||||
bankOrder.setSignatoryUser(signatoryUser);
|
||||
}
|
||||
|
||||
if (!bankOrderFileFormat.getIsMultiCurrency()) {
|
||||
bankOrder.setBankOrderCurrency(currency);
|
||||
}
|
||||
bankOrder.setCompanyCurrency(senderCompany.getCurrency());
|
||||
|
||||
bankOrder.setSenderReference(senderReference);
|
||||
bankOrder.setSenderLabel(senderLabel);
|
||||
bankOrder.setBankOrderLineList(new ArrayList<BankOrderLine>());
|
||||
bankOrder.setBankOrderFileFormat(bankOrderFileFormat);
|
||||
bankOrder.setTechnicalOriginSelect(technicalOriginSelect);
|
||||
return bankOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a bank order for an invoice Payment
|
||||
*
|
||||
* @param invoicePayment An invoice payment
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public BankOrder createBankOrder(InvoicePayment invoicePayment) throws AxelorException {
|
||||
Invoice invoice = invoicePayment.getInvoice();
|
||||
Company company = invoice.getCompany();
|
||||
PaymentMode paymentMode = invoicePayment.getPaymentMode();
|
||||
Partner partner = invoice.getPartner();
|
||||
BigDecimal amount = invoicePayment.getAmount();
|
||||
Currency currency = invoicePayment.getCurrency();
|
||||
LocalDate paymentDate = invoicePayment.getPaymentDate();
|
||||
BankDetails companyBankDetails =
|
||||
invoicePayment.getCompanyBankDetails() != null
|
||||
? invoicePayment.getCompanyBankDetails()
|
||||
: this.getSenderBankDetails(invoice);
|
||||
|
||||
String reference =
|
||||
InvoiceToolService.isPurchase(invoice)
|
||||
? invoice.getSupplierInvoiceNb()
|
||||
: invoice.getInvoiceId();
|
||||
|
||||
BankOrder bankOrder =
|
||||
this.createBankOrder(
|
||||
paymentMode,
|
||||
this.getBankOrderPartnerType(invoice),
|
||||
paymentDate,
|
||||
company,
|
||||
companyBankDetails,
|
||||
currency,
|
||||
reference,
|
||||
null,
|
||||
BankOrderRepository.TECHNICAL_ORIGIN_AUTOMATIC);
|
||||
|
||||
BankDetails receiverBankDetails = invoiceService.getBankDetails(invoice);
|
||||
BankOrderLine bankOrderLine =
|
||||
bankOrderLineService.createBankOrderLine(
|
||||
paymentMode.getBankOrderFileFormat(),
|
||||
null,
|
||||
partner,
|
||||
receiverBankDetails,
|
||||
amount,
|
||||
currency,
|
||||
paymentDate,
|
||||
reference,
|
||||
null,
|
||||
invoice);
|
||||
bankOrder.addBankOrderLineListItem(bankOrderLine);
|
||||
|
||||
bankOrder = bankOrderRepo.save(bankOrder);
|
||||
|
||||
return bankOrder;
|
||||
}
|
||||
|
||||
public int getBankOrderPartnerType(Invoice invoice) {
|
||||
|
||||
if (invoice.getOperationTypeSelect() == InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND
|
||||
|| invoice.getOperationTypeSelect() == InvoiceRepository.OPERATION_TYPE_CLIENT_SALE) {
|
||||
return BankOrderRepository.PARTNER_TYPE_CUSTOMER;
|
||||
} else {
|
||||
return BankOrderRepository.PARTNER_TYPE_SUPPLIER;
|
||||
}
|
||||
}
|
||||
|
||||
public BankDetails getSenderBankDetails(Invoice invoice) {
|
||||
|
||||
if (invoice.getBankDetails() != null) {
|
||||
return invoice.getCompanyBankDetails();
|
||||
}
|
||||
|
||||
return invoice.getCompany().getDefaultBankDetails();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLineOrigin;
|
||||
import com.axelor.db.Model;
|
||||
|
||||
public interface BankOrderLineOriginService {
|
||||
|
||||
public BankOrderLineOrigin createBankOrderLineOrigin(Model model);
|
||||
|
||||
public boolean existBankOrderLineOrigin(BankOrder bankOrder, Model model);
|
||||
}
|
||||
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder;
|
||||
|
||||
import com.axelor.apps.account.db.Invoice;
|
||||
import com.axelor.apps.account.db.PaymentScheduleLine;
|
||||
import com.axelor.apps.account.db.Reimbursement;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLineOrigin;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderLineOriginRepository;
|
||||
import com.axelor.db.EntityHelper;
|
||||
import com.axelor.db.Model;
|
||||
import com.google.inject.Inject;
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class BankOrderLineOriginServiceImpl implements BankOrderLineOriginService {
|
||||
|
||||
protected BankOrderLineOriginRepository bankOrderLineOriginRepository;
|
||||
|
||||
@Inject
|
||||
public BankOrderLineOriginServiceImpl(
|
||||
BankOrderLineOriginRepository bankOrderLineOriginRepository) {
|
||||
this.bankOrderLineOriginRepository = bankOrderLineOriginRepository;
|
||||
}
|
||||
|
||||
public BankOrderLineOrigin createBankOrderLineOrigin(Model model) {
|
||||
|
||||
Class<?> klass = EntityHelper.getEntityClass(model);
|
||||
|
||||
return this.createBankOrderLineOrigin(
|
||||
klass.getCanonicalName(),
|
||||
model.getId(),
|
||||
computeRelatedToSelectName(model),
|
||||
computeRelatedToSelectDate(model),
|
||||
computeRelatedToSelectDueDate(model));
|
||||
}
|
||||
|
||||
protected String computeRelatedToSelectName(Model model) {
|
||||
|
||||
if (model instanceof Invoice) {
|
||||
|
||||
return ((Invoice) model).getInvoiceId();
|
||||
|
||||
} else if (model instanceof PaymentScheduleLine) {
|
||||
|
||||
return ((PaymentScheduleLine) model).getName();
|
||||
|
||||
} else if (model instanceof Reimbursement) {
|
||||
|
||||
return ((Reimbursement) model).getRef();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected LocalDate computeRelatedToSelectDate(Model model) {
|
||||
if (model instanceof Invoice) {
|
||||
|
||||
return ((Invoice) model).getInvoiceDate();
|
||||
|
||||
} else if (model instanceof PaymentScheduleLine) {
|
||||
|
||||
return ((PaymentScheduleLine) model).getScheduleDate();
|
||||
|
||||
} else if (model instanceof Reimbursement) {
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected LocalDate computeRelatedToSelectDueDate(Model model) {
|
||||
if (model instanceof Invoice) {
|
||||
|
||||
return ((Invoice) model).getDueDate();
|
||||
|
||||
} else if (model instanceof PaymentScheduleLine) {
|
||||
|
||||
return ((PaymentScheduleLine) model).getScheduleDate();
|
||||
|
||||
} else if (model instanceof Reimbursement) {
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected BankOrderLineOrigin createBankOrderLineOrigin(
|
||||
String relatedToSelect,
|
||||
Long relatedToSelectId,
|
||||
String relatedToSelectName,
|
||||
LocalDate relatedToSelectDate,
|
||||
LocalDate relatedToSelectDueDate) {
|
||||
BankOrderLineOrigin bankOrderLineOrigin = new BankOrderLineOrigin();
|
||||
|
||||
bankOrderLineOrigin.setRelatedToSelect(relatedToSelect);
|
||||
bankOrderLineOrigin.setRelatedToSelectId(relatedToSelectId);
|
||||
bankOrderLineOrigin.setRelatedToSelectName(relatedToSelectName);
|
||||
bankOrderLineOrigin.setRelatedToSelectDate(relatedToSelectDate);
|
||||
bankOrderLineOrigin.setRelatedToSelectDueDate(relatedToSelectDueDate);
|
||||
|
||||
return bankOrderLineOrigin;
|
||||
}
|
||||
|
||||
public boolean existBankOrderLineOrigin(BankOrder bankOrder, Model model) {
|
||||
|
||||
Class<?> klass = EntityHelper.getEntityClass(model);
|
||||
|
||||
Long count =
|
||||
bankOrderLineOriginRepository
|
||||
.all()
|
||||
.filter(
|
||||
"self.relatedToSelect = ?1 AND self.relatedToSelectId = ?2",
|
||||
klass.getCanonicalName(),
|
||||
model.getId())
|
||||
.count();
|
||||
|
||||
if (count != null && count > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,456 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderFileFormat;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderFileFormatRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsPartnerRepository;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.base.db.Address;
|
||||
import com.axelor.apps.base.db.Bank;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Currency;
|
||||
import com.axelor.apps.base.db.Partner;
|
||||
import com.axelor.apps.base.db.repo.BankDetailsRepository;
|
||||
import com.axelor.apps.base.service.CurrencyService;
|
||||
import com.axelor.apps.base.service.PartnerService;
|
||||
import com.axelor.apps.tool.StringTool;
|
||||
import com.axelor.db.Model;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.meta.CallMethod;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BankOrderLineService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
protected BankDetailsRepository bankDetailsRepo;
|
||||
protected CurrencyService currencyService;
|
||||
protected BankOrderLineOriginService bankOrderLineOriginService;
|
||||
|
||||
@Inject
|
||||
public BankOrderLineService(
|
||||
BankDetailsRepository bankDetailsRepo,
|
||||
CurrencyService currencyService,
|
||||
BankOrderLineOriginService bankOrderLineOriginService) {
|
||||
|
||||
this.bankDetailsRepo = bankDetailsRepo;
|
||||
this.currencyService = currencyService;
|
||||
this.bankOrderLineOriginService = bankOrderLineOriginService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a specific BankOrderLine for SEPA and international transfer and direct debit
|
||||
*
|
||||
* @param partner
|
||||
* @param amount
|
||||
* @param receiverReference
|
||||
* @param receiverLabel
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public BankOrderLine createBankOrderLine(
|
||||
BankOrderFileFormat bankOrderFileFormat,
|
||||
Partner partner,
|
||||
BigDecimal amount,
|
||||
Currency currency,
|
||||
LocalDate bankOrderDate,
|
||||
String receiverReference,
|
||||
String receiverLabel,
|
||||
Model origin)
|
||||
throws AxelorException {
|
||||
|
||||
BankDetails receiverBankDetails = bankDetailsRepo.findDefaultByPartner(partner);
|
||||
|
||||
return this.createBankOrderLine(
|
||||
bankOrderFileFormat,
|
||||
null,
|
||||
partner,
|
||||
receiverBankDetails,
|
||||
amount,
|
||||
currency,
|
||||
bankOrderDate,
|
||||
receiverReference,
|
||||
receiverLabel,
|
||||
origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a specific BankOrderLine for treasury transfer
|
||||
*
|
||||
* @param receiverCompany
|
||||
* @param amount
|
||||
* @param receiverReference
|
||||
* @param receiverLabel
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public BankOrderLine createBankOrderLine(
|
||||
BankOrderFileFormat bankOrderFileFormat,
|
||||
Company receiverCompany,
|
||||
BigDecimal amount,
|
||||
Currency currency,
|
||||
LocalDate bankOrderDate,
|
||||
String receiverReference,
|
||||
String receiverLabel,
|
||||
Model origin)
|
||||
throws AxelorException {
|
||||
|
||||
return this.createBankOrderLine(
|
||||
bankOrderFileFormat,
|
||||
receiverCompany,
|
||||
receiverCompany.getPartner(),
|
||||
receiverCompany.getDefaultBankDetails(),
|
||||
amount,
|
||||
currency,
|
||||
bankOrderDate,
|
||||
receiverReference,
|
||||
receiverLabel,
|
||||
origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic method to create a BankOrderLine
|
||||
*
|
||||
* @param receiverCompany
|
||||
* @param partner
|
||||
* @param bankDetails
|
||||
* @param amount
|
||||
* @param receiverReference
|
||||
* @param receiverLabel
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
*/
|
||||
public BankOrderLine createBankOrderLine(
|
||||
BankOrderFileFormat bankOrderFileFormat,
|
||||
Company receiverCompany,
|
||||
Partner partner,
|
||||
BankDetails bankDetails,
|
||||
BigDecimal amount,
|
||||
Currency currency,
|
||||
LocalDate bankOrderDate,
|
||||
String receiverReference,
|
||||
String receiverLabel,
|
||||
Model origin)
|
||||
throws AxelorException {
|
||||
|
||||
BankOrderLine bankOrderLine = new BankOrderLine();
|
||||
|
||||
bankOrderLine.setReceiverCompany(receiverCompany);
|
||||
bankOrderLine.setPartner(partner);
|
||||
bankOrderLine.setReceiverBankDetails(bankDetails);
|
||||
bankOrderLine.setBankOrderAmount(amount);
|
||||
|
||||
if (bankOrderFileFormat.getIsMultiCurrency()) {
|
||||
bankOrderLine.setBankOrderCurrency(currency);
|
||||
}
|
||||
|
||||
if (bankOrderFileFormat.getIsMultiDate()) {
|
||||
bankOrderLine.setBankOrderDate(bankOrderDate);
|
||||
}
|
||||
|
||||
bankOrderLine.setReceiverReference(receiverReference);
|
||||
bankOrderLine.setReceiverLabel(receiverLabel);
|
||||
|
||||
if (origin != null) {
|
||||
bankOrderLine.addBankOrderLineOriginListItem(
|
||||
bankOrderLineOriginService.createBankOrderLineOrigin(origin));
|
||||
}
|
||||
|
||||
if (bankOrderFileFormat
|
||||
.getOrderFileFormatSelect()
|
||||
.equals(BankOrderFileFormatRepository.FILE_FORMAT_PAIN_XXX_CFONB320_XCT)) {
|
||||
bankOrderLine.setBankOrderEconomicReason(bankOrderFileFormat.getBankOrderEconomicReason());
|
||||
bankOrderLine.setReceiverCountry(bankOrderFileFormat.getReceiverCountry());
|
||||
|
||||
if (bankDetails != null) {
|
||||
Bank bank = bankDetails.getBank();
|
||||
if (bank != null && bank.getCountry() != null) {
|
||||
bankOrderLine.setReceiverCountry(bank.getCountry());
|
||||
}
|
||||
} else {
|
||||
throw new AxelorException(
|
||||
bankOrderLine,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_BANK_DETAILS_MISSING));
|
||||
}
|
||||
|
||||
bankOrderLine.setPaymentModeSelect(bankOrderFileFormat.getPaymentModeSelect());
|
||||
bankOrderLine.setFeesImputationModeSelect(bankOrderFileFormat.getFeesImputationModeSelect());
|
||||
bankOrderLine.setReceiverAddressStr(getReceiverAddress(partner));
|
||||
}
|
||||
|
||||
return bankOrderLine;
|
||||
}
|
||||
|
||||
@CallMethod
|
||||
public String getReceiverAddress(Partner partner) {
|
||||
|
||||
Address receiverAddress = Beans.get(PartnerService.class).getInvoicingAddress(partner);
|
||||
return receiverAddress != null ? receiverAddress.getFullName() : "";
|
||||
}
|
||||
|
||||
public void checkPreconditions(BankOrderLine bankOrderLine) throws AxelorException {
|
||||
|
||||
if (bankOrderLine.getBankOrder().getPartnerTypeSelect()
|
||||
== BankOrderRepository.PARTNER_TYPE_COMPANY) {
|
||||
if (bankOrderLine.getReceiverCompany() == null) {
|
||||
throw new AxelorException(
|
||||
bankOrderLine,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_COMPANY_MISSING));
|
||||
}
|
||||
}
|
||||
if (bankOrderLine.getPartner() == null) {
|
||||
throw new AxelorException(
|
||||
bankOrderLine,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_PARTNER_MISSING));
|
||||
}
|
||||
if (bankOrderLine.getReceiverBankDetails() == null) {
|
||||
throw new AxelorException(
|
||||
bankOrderLine,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_BANK_DETAILS_MISSING));
|
||||
}
|
||||
if (bankOrderLine.getBankOrderAmount().compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new AxelorException(
|
||||
bankOrderLine,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_AMOUNT_NEGATIVE));
|
||||
}
|
||||
}
|
||||
|
||||
public String createDomainForBankDetails(BankOrderLine bankOrderLine, BankOrder bankOrder) {
|
||||
String domain = "";
|
||||
String bankDetailsIds = "";
|
||||
|
||||
if ((bankOrderLine == null) || (bankOrder == null)) {
|
||||
return domain;
|
||||
}
|
||||
|
||||
// the case where the bank order is for a company
|
||||
if (bankOrder.getPartnerTypeSelect() == BankOrderRepository.PARTNER_TYPE_COMPANY) {
|
||||
if (bankOrderLine.getReceiverCompany() != null) {
|
||||
|
||||
bankDetailsIds =
|
||||
StringTool.getIdListString(bankOrderLine.getReceiverCompany().getBankDetailsSet());
|
||||
|
||||
if (bankOrderLine.getReceiverCompany().getDefaultBankDetails() != null) {
|
||||
bankDetailsIds += bankDetailsIds.equals("") ? "" : ",";
|
||||
bankDetailsIds +=
|
||||
bankOrderLine.getReceiverCompany().getDefaultBankDetails().getId().toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// case where the bank order is for a partner
|
||||
else if (bankOrderLine.getPartner() != null) {
|
||||
bankDetailsIds = StringTool.getIdListString(bankOrderLine.getPartner().getBankDetailsList());
|
||||
}
|
||||
|
||||
if (bankDetailsIds.equals("")) {
|
||||
return domain = "";
|
||||
}
|
||||
|
||||
domain = "self.id IN(" + bankDetailsIds + ")";
|
||||
|
||||
// filter the result on active bank details
|
||||
domain += " AND self.active = true";
|
||||
|
||||
// filter on the result from bankPartner if the option is active.
|
||||
EbicsPartner ebicsPartner =
|
||||
Beans.get(EbicsPartnerRepository.class)
|
||||
.all()
|
||||
.filter("? MEMBER OF self.bankDetailsSet", bankOrder.getSenderBankDetails())
|
||||
.fetchOne();
|
||||
|
||||
if (ebicsPartnerIsFiltering(ebicsPartner, bankOrder.getOrderTypeSelect())) {
|
||||
domain +=
|
||||
" AND self.id IN ("
|
||||
+ StringTool.getIdListString(ebicsPartner.getReceiverBankDetailsSet())
|
||||
+ ")";
|
||||
}
|
||||
|
||||
// filter on the bank details identifier type from the bank order file format
|
||||
if (bankOrder.getBankOrderFileFormat() != null) {
|
||||
String acceptedIdentifiers = bankOrder.getBankOrderFileFormat().getBankDetailsTypeSelect();
|
||||
if (acceptedIdentifiers != null && !acceptedIdentifiers.equals("")) {
|
||||
domain += " AND self.bank.bankDetailsTypeSelect IN (" + acceptedIdentifiers + ")";
|
||||
}
|
||||
}
|
||||
// filter on the currency if it is set in bank order and in the bankdetails
|
||||
// and if the bankOrder is not multicurrency
|
||||
// and if the partner type select is a company
|
||||
Currency currency = bankOrder.getBankOrderCurrency();
|
||||
if (!bankOrder.getIsMultiCurrency()
|
||||
&& currency != null
|
||||
&& bankOrder.getPartnerTypeSelect() == BankOrderRepository.PARTNER_TYPE_COMPANY) {
|
||||
String fileFormatCurrencyId = currency.getId().toString();
|
||||
domain += " AND (self.currency IS NULL OR self.currency.id = " + fileFormatCurrencyId + ")";
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the default bank detail in receiver company if partner type select is company. If not
|
||||
* company, search default in partner of bank order line. If no default bank detail, return the
|
||||
* alone bank detail present if is active in the partner of bank order line.
|
||||
*
|
||||
* @param bankOrderLine The bank order line
|
||||
* @param bankOrder The bank order
|
||||
* @return default bank detail if present otherwise the unique bank detail if active
|
||||
*/
|
||||
public BankDetails getDefaultBankDetails(BankOrderLine bankOrderLine, BankOrder bankOrder) {
|
||||
BankDetails candidateBankDetails = null;
|
||||
if (bankOrder.getPartnerTypeSelect() == BankOrderRepository.PARTNER_TYPE_COMPANY
|
||||
&& bankOrderLine.getReceiverCompany() != null) {
|
||||
candidateBankDetails = bankOrderLine.getReceiverCompany().getDefaultBankDetails();
|
||||
if (candidateBankDetails == null) {
|
||||
for (BankDetails bankDetails : bankOrderLine.getReceiverCompany().getBankDetailsSet()) {
|
||||
if (candidateBankDetails != null && bankDetails.getActive()) {
|
||||
candidateBankDetails = null;
|
||||
break;
|
||||
} else if (bankDetails.getActive()) {
|
||||
candidateBankDetails = bankDetails;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (bankOrder.getPartnerTypeSelect() != BankOrderRepository.PARTNER_TYPE_COMPANY
|
||||
&& bankOrderLine.getPartner() != null) {
|
||||
candidateBankDetails = bankDetailsRepo.findDefaultByPartner(bankOrderLine.getPartner());
|
||||
if (candidateBankDetails == null) {
|
||||
List<BankDetails> bankDetailsList =
|
||||
bankDetailsRepo.findActivesByPartner(bankOrderLine.getPartner(), true).fetch();
|
||||
if (bankDetailsList.size() == 1) {
|
||||
candidateBankDetails = bankDetailsList.get(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
checkBankDetails(candidateBankDetails, bankOrder);
|
||||
} catch (AxelorException e) {
|
||||
candidateBankDetails = null;
|
||||
}
|
||||
|
||||
return candidateBankDetails;
|
||||
}
|
||||
|
||||
public void checkBankDetails(BankDetails bankDetails, BankOrder bankOrder)
|
||||
throws AxelorException {
|
||||
if (bankDetails == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_BANK_DETAILS_MISSING));
|
||||
}
|
||||
|
||||
// check if the bank details is active
|
||||
if (!bankDetails.getActive()) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_BANK_DETAILS_NOT_ACTIVE));
|
||||
}
|
||||
|
||||
// filter on the result from bankPartner if the option is active.
|
||||
EbicsPartner ebicsPartner =
|
||||
Beans.get(EbicsPartnerRepository.class)
|
||||
.all()
|
||||
.filter("? MEMBER OF self.bankDetailsSet", bankOrder.getSenderBankDetails())
|
||||
.fetchOne();
|
||||
|
||||
if (ebicsPartnerIsFiltering(ebicsPartner, bankOrder.getOrderTypeSelect())) {
|
||||
|
||||
if (!ebicsPartner.getReceiverBankDetailsSet().contains(bankDetails)) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_BANK_DETAILS_FORBIDDEN));
|
||||
}
|
||||
}
|
||||
|
||||
// filter on the bank details identifier type from the bank order file format
|
||||
if (bankOrder.getBankOrderFileFormat() != null) {
|
||||
if (!Beans.get(BankOrderService.class)
|
||||
.checkBankDetailsTypeCompatible(bankDetails, bankOrder.getBankOrderFileFormat())) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_BANK_DETAILS_TYPE_NOT_COMPATIBLE));
|
||||
}
|
||||
}
|
||||
|
||||
// filter on the currency if the bank order is not multicurrency
|
||||
// and if the partner type select is a company
|
||||
if (!bankOrder.getIsMultiCurrency()
|
||||
&& bankOrder.getBankOrderCurrency() != null
|
||||
&& bankOrder.getPartnerTypeSelect() == BankOrderRepository.PARTNER_TYPE_COMPANY) {
|
||||
if (!Beans.get(BankOrderService.class)
|
||||
.checkBankDetailsCurrencyCompatible(bankDetails, bankOrder)) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_BANK_DETAILS_CURRENCY_NOT_COMPATIBLE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean ebicsPartnerIsFiltering(EbicsPartner ebicsPartner, int orderType) {
|
||||
return (ebicsPartner != null)
|
||||
&& (ebicsPartner.getFilterReceiverBD())
|
||||
&& (ebicsPartner.getReceiverBankDetailsSet() != null)
|
||||
&& (!ebicsPartner.getReceiverBankDetailsSet().isEmpty())
|
||||
&& (ebicsPartner.getOrderTypeSelect() == orderType);
|
||||
}
|
||||
|
||||
public BigDecimal computeCompanyCurrencyAmount(BankOrder bankOrder, BankOrderLine bankOrderLine)
|
||||
throws AxelorException {
|
||||
|
||||
LocalDate bankOrderDate = bankOrder.getBankOrderDate();
|
||||
|
||||
if (bankOrder.getIsMultiDate()) {
|
||||
bankOrderDate = bankOrderLine.getBankOrderDate();
|
||||
}
|
||||
|
||||
Currency bankOrderCurrency = bankOrder.getBankOrderCurrency();
|
||||
|
||||
if (bankOrder.getIsMultiCurrency()) {
|
||||
bankOrderCurrency = bankOrderLine.getBankOrderCurrency();
|
||||
}
|
||||
|
||||
return currencyService
|
||||
.getAmountCurrencyConvertedAtDate(
|
||||
bankOrderCurrency,
|
||||
bankOrder.getCompanyCurrency(),
|
||||
bankOrderLine.getBankOrderAmount(),
|
||||
bankOrderDate)
|
||||
.setScale(2, RoundingMode.HALF_UP); // TODO Manage the number of decimal for currency
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder;
|
||||
|
||||
import com.axelor.apps.account.db.InvoicePayment;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.util.Collection;
|
||||
|
||||
public interface BankOrderMergeService {
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public BankOrder mergeBankOrders(Collection<BankOrder> bankOrders) throws AxelorException;
|
||||
|
||||
/**
|
||||
* Merge bank orders from invoice payments.
|
||||
*
|
||||
* @param invoicePayments
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
*/
|
||||
BankOrder mergeFromInvoicePayments(Collection<InvoicePayment> invoicePayments)
|
||||
throws AxelorException;
|
||||
}
|
||||
@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder;
|
||||
|
||||
import com.axelor.apps.account.db.Invoice;
|
||||
import com.axelor.apps.account.db.InvoicePayment;
|
||||
import com.axelor.apps.account.db.PaymentMode;
|
||||
import com.axelor.apps.account.db.PaymentScheduleLine;
|
||||
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
|
||||
import com.axelor.apps.account.db.repo.InvoiceRepository;
|
||||
import com.axelor.apps.account.db.repo.PaymentScheduleLineRepository;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLineOrigin;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderLineOriginRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderRepository;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Currency;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BankOrderMergeServiceImpl implements BankOrderMergeService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
protected BankOrderRepository bankOrderRepo;
|
||||
protected InvoicePaymentRepository invoicePaymentRepo;
|
||||
protected BankOrderService bankOrderService;
|
||||
protected InvoiceRepository invoiceRepository;
|
||||
protected PaymentScheduleLineRepository paymentScheduleLineRepository;
|
||||
|
||||
@Inject
|
||||
public BankOrderMergeServiceImpl(
|
||||
BankOrderRepository bankOrderRepo,
|
||||
InvoicePaymentRepository invoicePaymentRepo,
|
||||
BankOrderService bankOrderService,
|
||||
InvoiceRepository invoiceRepository,
|
||||
PaymentScheduleLineRepository paymentScheduleLineRepository) {
|
||||
|
||||
this.bankOrderRepo = bankOrderRepo;
|
||||
this.invoicePaymentRepo = invoicePaymentRepo;
|
||||
this.bankOrderService = bankOrderService;
|
||||
this.invoiceRepository = invoiceRepository;
|
||||
this.paymentScheduleLineRepository = paymentScheduleLineRepository;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public BankOrder mergeBankOrders(Collection<BankOrder> bankOrders) throws AxelorException {
|
||||
|
||||
if (bankOrders == null || bankOrders.size() <= 1) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
IExceptionMessage.BANK_ORDER_MERGE_AT_LEAST_TWO_BANK_ORDERS);
|
||||
}
|
||||
|
||||
this.checkSameElements(bankOrders);
|
||||
|
||||
BankOrder bankOrder = bankOrders.iterator().next();
|
||||
|
||||
bankOrders.remove(bankOrder);
|
||||
|
||||
bankOrder.setSenderLabel(null);
|
||||
bankOrder.setSenderReference(null);
|
||||
bankOrder.setBankOrderDate(Beans.get(AppBaseService.class).getTodayDate());
|
||||
bankOrder.setSignatoryUser(null);
|
||||
bankOrder.setSignatoryEbicsUser(null);
|
||||
|
||||
PaymentMode paymentMode = bankOrder.getPaymentMode();
|
||||
|
||||
for (BankOrderLine bankOrderLine : this.getAllBankOrderLineList(bankOrders)) {
|
||||
|
||||
bankOrder.addBankOrderLineListItem(bankOrderLine);
|
||||
}
|
||||
|
||||
bankOrderRepo.save(bankOrder);
|
||||
|
||||
for (BankOrder bankOrderToRemove : bankOrders) {
|
||||
|
||||
bankOrderToRemove = bankOrderRepo.find(bankOrderToRemove.getId());
|
||||
|
||||
List<InvoicePayment> invoicePaymentList =
|
||||
invoicePaymentRepo.findByBankOrder(bankOrderToRemove).fetch();
|
||||
|
||||
for (InvoicePayment invoicePayment : invoicePaymentList) {
|
||||
|
||||
invoicePayment.setBankOrder(bankOrder);
|
||||
}
|
||||
|
||||
bankOrderRepo.remove(bankOrderToRemove);
|
||||
}
|
||||
|
||||
if (paymentMode.getConsoBankOrderLinePerPartner()) {
|
||||
|
||||
consolidatePerPartner(bankOrder);
|
||||
}
|
||||
|
||||
bankOrderService.updateTotalAmounts(bankOrder);
|
||||
|
||||
return bankOrderRepo.save(bankOrder);
|
||||
}
|
||||
|
||||
protected void checkSameElements(Collection<BankOrder> bankOrders) throws AxelorException {
|
||||
|
||||
BankOrder refBankOrder = bankOrders.iterator().next();
|
||||
|
||||
int refStatusSelect = refBankOrder.getStatusSelect();
|
||||
int orderTypeSelect = refBankOrder.getOrderTypeSelect();
|
||||
PaymentMode refPaymentMode = refBankOrder.getPaymentMode();
|
||||
int refPartnerTypeSelect = refBankOrder.getPartnerTypeSelect();
|
||||
Company refSenderCompany = refBankOrder.getSenderCompany();
|
||||
BankDetails refSenderBankDetails = refBankOrder.getSenderBankDetails();
|
||||
Currency refCurrency = refBankOrder.getBankOrderCurrency();
|
||||
boolean isMultiCurrency = refBankOrder.getIsMultiCurrency();
|
||||
|
||||
for (BankOrder bankOrder : bankOrders) {
|
||||
|
||||
int statusSelect = bankOrder.getStatusSelect();
|
||||
if (statusSelect != BankOrderRepository.STATUS_DRAFT
|
||||
&& statusSelect != BankOrderRepository.STATUS_AWAITING_SIGNATURE) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_MERGE_STATUS));
|
||||
}
|
||||
|
||||
if (statusSelect != refStatusSelect) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_MERGE_SAME_STATUS));
|
||||
}
|
||||
|
||||
if (!bankOrder.getOrderTypeSelect().equals(orderTypeSelect)) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_MERGE_SAME_ORDER_TYPE_SELECT));
|
||||
}
|
||||
|
||||
if (!bankOrder.getPaymentMode().equals(refPaymentMode)) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_MERGE_SAME_PAYMENT_MODE));
|
||||
}
|
||||
|
||||
if (!bankOrder.getPartnerTypeSelect().equals(refPartnerTypeSelect)) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_MERGE_SAME_PARTNER_TYPE_SELECT));
|
||||
}
|
||||
|
||||
if (!bankOrder.getSenderCompany().equals(refSenderCompany)) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_MERGE_SAME_SENDER_COMPANY));
|
||||
}
|
||||
|
||||
if (bankOrder.getSenderBankDetails() == null && refSenderBankDetails != null
|
||||
|| (bankOrder.getSenderBankDetails() != null
|
||||
&& !bankOrder.getSenderBankDetails().equals(refSenderBankDetails))) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_MERGE_SAME_SENDER_BANK_DETAILS));
|
||||
}
|
||||
|
||||
if (bankOrder.getIsMultiCurrency() != isMultiCurrency
|
||||
|| !bankOrder.getIsMultiCurrency()
|
||||
&& !bankOrder.getBankOrderCurrency().equals(refCurrency)) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_MERGE_SAME_CURRENCY));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected List<BankOrderLine> getAllBankOrderLineList(Collection<BankOrder> bankOrders) {
|
||||
|
||||
List<BankOrderLine> bankOrderLineList = Lists.newArrayList();
|
||||
|
||||
for (BankOrder bankOrder : bankOrders) {
|
||||
|
||||
bankOrderLineList.addAll(bankOrder.getBankOrderLineList());
|
||||
}
|
||||
|
||||
return bankOrderLineList;
|
||||
}
|
||||
|
||||
public void consolidatePerPartner(BankOrder bankOrder) {
|
||||
|
||||
Map<List<Object>, BankOrderLine> bankOrderLineMap = new HashMap<List<Object>, BankOrderLine>();
|
||||
|
||||
int counter = 1;
|
||||
|
||||
for (BankOrderLine bankOrderLine : bankOrder.getBankOrderLineList()) {
|
||||
|
||||
List<Object> keys = new ArrayList<Object>();
|
||||
keys.add(bankOrderLine.getPartner());
|
||||
keys.add(bankOrderLine.getBankOrderCurrency());
|
||||
keys.add(bankOrderLine.getBankOrderDate());
|
||||
keys.add(bankOrderLine.getBankOrderEconomicReason());
|
||||
keys.add(bankOrderLine.getFeesImputationModeSelect());
|
||||
keys.add(bankOrderLine.getPaymentModeSelect());
|
||||
keys.add(bankOrderLine.getReceiverBankDetails());
|
||||
keys.add(bankOrderLine.getReceiverCompany());
|
||||
|
||||
if (bankOrderLineMap.containsKey(keys)) {
|
||||
BankOrderLine consolidateBankOrderLine = bankOrderLineMap.get(keys);
|
||||
if (consolidateBankOrderLine.getBankOrderLineOriginList() == null) {
|
||||
consolidateBankOrderLine.setBankOrderLineOriginList(new ArrayList<>());
|
||||
}
|
||||
if (bankOrderLine.getBankOrderLineOriginList() != null) {
|
||||
bankOrderLine
|
||||
.getBankOrderLineOriginList()
|
||||
.stream()
|
||||
.forEach(consolidateBankOrderLine::addBankOrderLineOriginListItem);
|
||||
}
|
||||
consolidateBankOrderLine.setBankOrderAmount(
|
||||
consolidateBankOrderLine.getBankOrderAmount().add(bankOrderLine.getBankOrderAmount()));
|
||||
consolidateBankOrderLine.setCompanyCurrencyAmount(
|
||||
consolidateBankOrderLine
|
||||
.getCompanyCurrencyAmount()
|
||||
.add(bankOrderLine.getCompanyCurrencyAmount()));
|
||||
} else {
|
||||
bankOrderLine.setCounter(counter++);
|
||||
bankOrderLineMap.put(keys, bankOrderLine);
|
||||
}
|
||||
}
|
||||
|
||||
bankOrder.getBankOrderLineList().clear();
|
||||
|
||||
for (BankOrderLine bankOrderLine : bankOrderLineMap.values()) {
|
||||
|
||||
Pair<String, LocalDate> lastReferences = getLastReferences(bankOrderLine);
|
||||
|
||||
bankOrderLine.setReceiverReference(lastReferences.getLeft());
|
||||
bankOrderLine.setBankOrderDate(lastReferences.getRight());
|
||||
bankOrder.addBankOrderLineListItem(bankOrderLine);
|
||||
}
|
||||
}
|
||||
|
||||
protected Pair<String, LocalDate> getLastReferences(BankOrderLine bankOrderLine) {
|
||||
|
||||
String lastReferenceId = "";
|
||||
LocalDate lastReferenceDate = null;
|
||||
|
||||
for (BankOrderLineOrigin bankOrderLineOrigin : bankOrderLine.getBankOrderLineOriginList()) {
|
||||
LocalDate originDate = null;
|
||||
String originReferenceId = null;
|
||||
|
||||
switch (bankOrderLineOrigin.getRelatedToSelect()) {
|
||||
case BankOrderLineOriginRepository.RELATED_TO_INVOICE:
|
||||
Invoice invoice = invoiceRepository.find(bankOrderLineOrigin.getRelatedToSelectId());
|
||||
if (!Strings.isNullOrEmpty(invoice.getSupplierInvoiceNb())) {
|
||||
originReferenceId = invoice.getSupplierInvoiceNb();
|
||||
} else {
|
||||
originReferenceId = invoice.getInvoiceId();
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(invoice.getSupplierInvoiceNb())) {
|
||||
originDate = invoice.getOriginDate();
|
||||
} else {
|
||||
originDate = invoice.getInvoiceDate();
|
||||
}
|
||||
break;
|
||||
|
||||
case BankOrderLineOriginRepository.RELATED_TO_PAYMENT_SCHEDULE_LINE:
|
||||
PaymentScheduleLine paymentScheduleLine =
|
||||
paymentScheduleLineRepository.find(bankOrderLineOrigin.getRelatedToSelectId());
|
||||
originReferenceId = paymentScheduleLine.getName();
|
||||
originDate = paymentScheduleLine.getScheduleDate();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (originDate != null
|
||||
&& (lastReferenceDate == null || lastReferenceDate.isBefore(originDate))) {
|
||||
lastReferenceDate = originDate;
|
||||
lastReferenceId = originReferenceId;
|
||||
}
|
||||
}
|
||||
|
||||
return Pair.of(lastReferenceId, lastReferenceDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public BankOrder mergeFromInvoicePayments(Collection<InvoicePayment> invoicePayments)
|
||||
throws AxelorException {
|
||||
|
||||
if (invoicePayments == null || invoicePayments.isEmpty()) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_MERGE_NO_BANK_ORDERS));
|
||||
}
|
||||
|
||||
Collection<InvoicePayment> invoicePaymentsWithBankOrders = new ArrayList<>();
|
||||
Collection<BankOrder> bankOrders = new LinkedHashSet<>();
|
||||
|
||||
for (InvoicePayment invoicePayment : invoicePayments) {
|
||||
BankOrder bankOrder = invoicePayment.getBankOrder();
|
||||
|
||||
if (bankOrder != null) {
|
||||
invoicePaymentsWithBankOrders.add(invoicePayment);
|
||||
bankOrders.add(bankOrder);
|
||||
}
|
||||
}
|
||||
|
||||
if (bankOrders.size() > 1) {
|
||||
LocalDate bankOrderDate = bankOrders.iterator().next().getBankOrderDate();
|
||||
BankOrder mergedBankOrder = mergeBankOrders(bankOrders);
|
||||
mergedBankOrder.setBankOrderDate(bankOrderDate);
|
||||
|
||||
for (InvoicePayment invoicePayment : invoicePaymentsWithBankOrders) {
|
||||
invoicePayment.setBankOrder(mergedBankOrder);
|
||||
}
|
||||
|
||||
return mergedBankOrder;
|
||||
}
|
||||
|
||||
if (!bankOrders.isEmpty()) {
|
||||
return bankOrders.iterator().next();
|
||||
}
|
||||
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_MERGE_NO_BANK_ORDERS));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.exception.AxelorException;
|
||||
|
||||
public interface BankOrderMoveService {
|
||||
|
||||
public void generateMoves(BankOrder bankOrder) throws AxelorException;
|
||||
}
|
||||
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder;
|
||||
|
||||
import com.axelor.apps.account.db.Account;
|
||||
import com.axelor.apps.account.db.AccountingSituation;
|
||||
import com.axelor.apps.account.db.Journal;
|
||||
import com.axelor.apps.account.db.Move;
|
||||
import com.axelor.apps.account.db.MoveLine;
|
||||
import com.axelor.apps.account.db.PaymentMode;
|
||||
import com.axelor.apps.account.db.repo.MoveRepository;
|
||||
import com.axelor.apps.account.service.AccountingSituationService;
|
||||
import com.axelor.apps.account.service.move.MoveService;
|
||||
import com.axelor.apps.account.service.payment.PaymentModeService;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderRepository;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.bankpayment.service.config.BankPaymentConfigService;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Currency;
|
||||
import com.axelor.apps.base.db.Partner;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.google.inject.Inject;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.time.LocalDate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BankOrderMoveServiceImpl implements BankOrderMoveService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
protected MoveService moveService;
|
||||
protected PaymentModeService paymentModeService;
|
||||
protected AccountingSituationService accountingSituationService;
|
||||
protected BankPaymentConfigService bankPaymentConfigService;
|
||||
|
||||
protected PaymentMode paymentMode;
|
||||
protected Company senderCompany;
|
||||
protected int orderTypeSelect;
|
||||
protected int partnerTypeSelect;
|
||||
protected Journal journal;
|
||||
protected Account senderBankAccount;
|
||||
protected BankDetails senderBankDetails;
|
||||
protected boolean isMultiDate;
|
||||
protected boolean isMultiCurrency;
|
||||
protected boolean isDebit;
|
||||
|
||||
@Inject
|
||||
public BankOrderMoveServiceImpl(
|
||||
MoveService moveService,
|
||||
PaymentModeService paymentModeService,
|
||||
AccountingSituationService accountingSituationService,
|
||||
BankPaymentConfigService bankPaymentConfigService) {
|
||||
|
||||
this.moveService = moveService;
|
||||
this.paymentModeService = paymentModeService;
|
||||
this.accountingSituationService = accountingSituationService;
|
||||
this.bankPaymentConfigService = bankPaymentConfigService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateMoves(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
if (bankOrder.getBankOrderLineList() == null || bankOrder.getBankOrderLineList().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
paymentMode = bankOrder.getPaymentMode();
|
||||
|
||||
if (paymentMode == null || !paymentMode.getGenerateMoveAutoFromBankOrder()) {
|
||||
return;
|
||||
}
|
||||
|
||||
orderTypeSelect = bankOrder.getOrderTypeSelect();
|
||||
senderCompany = bankOrder.getSenderCompany();
|
||||
senderBankDetails = bankOrder.getSenderBankDetails();
|
||||
partnerTypeSelect = bankOrder.getPartnerTypeSelect();
|
||||
|
||||
journal =
|
||||
paymentModeService.getPaymentModeJournal(paymentMode, senderCompany, senderBankDetails);
|
||||
senderBankAccount =
|
||||
paymentModeService.getPaymentModeAccount(paymentMode, senderCompany, senderBankDetails);
|
||||
|
||||
isMultiDate = bankOrder.getIsMultiDate();
|
||||
isMultiCurrency = bankOrder.getIsMultiCurrency();
|
||||
|
||||
if (orderTypeSelect == BankOrderRepository.ORDER_TYPE_INTERNATIONAL_CREDIT_TRANSFER
|
||||
|| orderTypeSelect == BankOrderRepository.ORDER_TYPE_SEPA_CREDIT_TRANSFER) {
|
||||
isDebit = true;
|
||||
} else {
|
||||
isDebit = false;
|
||||
}
|
||||
|
||||
for (BankOrderLine bankOrderLine : bankOrder.getBankOrderLineList()) {
|
||||
|
||||
generateMoves(bankOrderLine);
|
||||
}
|
||||
}
|
||||
|
||||
protected void generateMoves(BankOrderLine bankOrderLine) throws AxelorException {
|
||||
|
||||
bankOrderLine.setSenderMove(generateSenderMove(bankOrderLine));
|
||||
|
||||
if (partnerTypeSelect == BankOrderRepository.PARTNER_TYPE_COMPANY) {
|
||||
bankOrderLine.setReceiverMove(generateReceiverMove(bankOrderLine));
|
||||
}
|
||||
}
|
||||
|
||||
protected Move generateSenderMove(BankOrderLine bankOrderLine) throws AxelorException {
|
||||
|
||||
Partner partner = bankOrderLine.getPartner();
|
||||
|
||||
Move senderMove =
|
||||
moveService
|
||||
.getMoveCreateService()
|
||||
.createMove(
|
||||
journal,
|
||||
senderCompany,
|
||||
this.getCurrency(bankOrderLine),
|
||||
partner,
|
||||
this.getDate(bankOrderLine),
|
||||
paymentMode,
|
||||
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
|
||||
|
||||
MoveLine bankMoveLine =
|
||||
moveService
|
||||
.getMoveLineService()
|
||||
.createMoveLine(
|
||||
senderMove,
|
||||
partner,
|
||||
senderBankAccount,
|
||||
bankOrderLine.getBankOrderAmount(),
|
||||
!isDebit,
|
||||
senderMove.getDate(),
|
||||
1,
|
||||
bankOrderLine.getReceiverReference(),
|
||||
bankOrderLine.getReceiverLabel());
|
||||
senderMove.addMoveLineListItem(bankMoveLine);
|
||||
|
||||
MoveLine partnerMoveLine =
|
||||
moveService
|
||||
.getMoveLineService()
|
||||
.createMoveLine(
|
||||
senderMove,
|
||||
partner,
|
||||
getPartnerAccount(partner, senderCompany, senderCompany),
|
||||
bankOrderLine.getBankOrderAmount(),
|
||||
isDebit,
|
||||
senderMove.getDate(),
|
||||
2,
|
||||
bankOrderLine.getReceiverReference(),
|
||||
bankOrderLine.getReceiverLabel());
|
||||
senderMove.addMoveLineListItem(partnerMoveLine);
|
||||
|
||||
return senderMove;
|
||||
}
|
||||
|
||||
protected Move generateReceiverMove(BankOrderLine bankOrderLine) throws AxelorException {
|
||||
|
||||
Partner partner = bankOrderLine.getPartner();
|
||||
Company receiverCompany = bankOrderLine.getReceiverCompany();
|
||||
|
||||
BankDetails receiverBankDetails = bankOrderLine.getReceiverBankDetails();
|
||||
|
||||
Journal receiverJournal =
|
||||
paymentModeService.getPaymentModeJournal(paymentMode, receiverCompany, receiverBankDetails);
|
||||
Account receiverBankAccount =
|
||||
paymentModeService.getPaymentModeAccount(paymentMode, receiverCompany, receiverBankDetails);
|
||||
|
||||
Move receiverMove =
|
||||
moveService
|
||||
.getMoveCreateService()
|
||||
.createMove(
|
||||
receiverJournal,
|
||||
receiverCompany,
|
||||
this.getCurrency(bankOrderLine),
|
||||
partner,
|
||||
this.getDate(bankOrderLine),
|
||||
paymentMode,
|
||||
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
|
||||
|
||||
MoveLine bankMoveLine =
|
||||
moveService
|
||||
.getMoveLineService()
|
||||
.createMoveLine(
|
||||
receiverMove,
|
||||
partner,
|
||||
receiverBankAccount,
|
||||
bankOrderLine.getBankOrderAmount(),
|
||||
isDebit,
|
||||
receiverMove.getDate(),
|
||||
1,
|
||||
bankOrderLine.getReceiverReference(),
|
||||
bankOrderLine.getReceiverLabel());
|
||||
receiverMove.addMoveLineListItem(bankMoveLine);
|
||||
|
||||
MoveLine partnerMoveLine =
|
||||
moveService
|
||||
.getMoveLineService()
|
||||
.createMoveLine(
|
||||
receiverMove,
|
||||
partner,
|
||||
getPartnerAccount(partner, receiverCompany, receiverMove.getCompany()),
|
||||
bankOrderLine.getBankOrderAmount(),
|
||||
!isDebit,
|
||||
receiverMove.getDate(),
|
||||
2,
|
||||
bankOrderLine.getReceiverReference(),
|
||||
bankOrderLine.getReceiverLabel());
|
||||
receiverMove.addMoveLineListItem(partnerMoveLine);
|
||||
|
||||
return receiverMove;
|
||||
}
|
||||
|
||||
protected Account getPartnerAccount(Partner partner, Company receiverCompany, Company moveCompany)
|
||||
throws AxelorException {
|
||||
|
||||
AccountingSituation accountingSituation =
|
||||
accountingSituationService.getAccountingSituation(partner, receiverCompany);
|
||||
|
||||
switch (partnerTypeSelect) {
|
||||
case BankOrderRepository.PARTNER_TYPE_CUSTOMER:
|
||||
return accountingSituationService.getCustomerAccount(partner, receiverCompany);
|
||||
|
||||
case BankOrderRepository.PARTNER_TYPE_EMPLOYEE:
|
||||
return accountingSituationService.getEmployeeAccount(partner, receiverCompany);
|
||||
|
||||
case BankOrderRepository.PARTNER_TYPE_SUPPLIER:
|
||||
return accountingSituationService.getSupplierAccount(partner, receiverCompany);
|
||||
|
||||
case BankOrderRepository.PARTNER_TYPE_COMPANY:
|
||||
if (receiverCompany.equals(senderCompany)) {
|
||||
return bankPaymentConfigService.getInternalBankToBankAccount(
|
||||
bankPaymentConfigService.getBankPaymentConfig(moveCompany));
|
||||
} else {
|
||||
return bankPaymentConfigService.getExternalBankToBankAccount(
|
||||
bankPaymentConfigService.getBankPaymentConfig(moveCompany));
|
||||
}
|
||||
|
||||
default:
|
||||
throw new AxelorException(
|
||||
accountingSituation,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_PARTNER_TYPE_MISSING),
|
||||
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION));
|
||||
}
|
||||
}
|
||||
|
||||
protected LocalDate getDate(BankOrderLine bankOrderLine) {
|
||||
|
||||
if (isMultiDate) {
|
||||
return bankOrderLine.getBankOrderDate();
|
||||
} else {
|
||||
return bankOrderLine.getBankOrder().getBankOrderDate();
|
||||
}
|
||||
}
|
||||
|
||||
protected Currency getCurrency(BankOrderLine bankOrderLine) {
|
||||
|
||||
if (isMultiCurrency) {
|
||||
return bankOrderLine.getBankOrderCurrency();
|
||||
} else {
|
||||
return bankOrderLine.getBankOrder().getBankOrderCurrency();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderFileFormat;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
|
||||
public interface BankOrderService {
|
||||
|
||||
public BigDecimal computeBankOrderTotalAmount(BankOrder bankOrder) throws AxelorException;
|
||||
|
||||
public BigDecimal computeCompanyCurrencyTotalAmount(BankOrder bankOrder) throws AxelorException;
|
||||
|
||||
public void updateTotalAmounts(BankOrder bankOrder) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void confirm(BankOrder bankOrder)
|
||||
throws AxelorException, JAXBException, IOException, DatatypeConfigurationException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void sign(BankOrder bankOrder);
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validate(BankOrder bankOrder)
|
||||
throws JAXBException, IOException, AxelorException, DatatypeConfigurationException;
|
||||
|
||||
public void realize(BankOrder bankOrder) throws AxelorException;
|
||||
|
||||
public File generateFile(BankOrder bankOrder)
|
||||
throws JAXBException, IOException, AxelorException, DatatypeConfigurationException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public BankOrder generateSequence(BankOrder bankOrder) throws AxelorException;
|
||||
|
||||
public void setSequenceOnBankOrderLines(BankOrder bankOrder);
|
||||
|
||||
public void checkLines(BankOrder bankOrder) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validatePayment(BankOrder bankOrder) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void cancelPayment(BankOrder bankOrder) throws AxelorException;
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void cancelBankOrder(BankOrder bankOrder) throws AxelorException;
|
||||
|
||||
@Transactional
|
||||
public EbicsUser getDefaultEbicsUserFromBankDetails(BankDetails bankDetails);
|
||||
|
||||
public String createDomainForBankDetails(BankOrder bankOrder);
|
||||
|
||||
public BankDetails getDefaultBankDetails(BankOrder bankOrder);
|
||||
|
||||
public void checkBankDetails(BankDetails bankDetails, BankOrder bankOrder) throws AxelorException;
|
||||
|
||||
public boolean checkBankDetailsTypeCompatible(
|
||||
BankDetails bankDetails, BankOrderFileFormat bankOrderFileFormat);
|
||||
|
||||
public boolean checkBankDetailsCurrencyCompatible(BankDetails bankDetails, BankOrder bankOrder);
|
||||
|
||||
public void resetReceivers(BankOrder bankOrder);
|
||||
|
||||
public ActionViewBuilder buildBankOrderLineView(
|
||||
String gridViewName, String formViewName, String viewDomain);
|
||||
}
|
||||
@ -0,0 +1,821 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder;
|
||||
|
||||
import com.axelor.apps.account.db.InvoicePayment;
|
||||
import com.axelor.apps.account.db.PaymentMode;
|
||||
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
|
||||
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCancelService;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderFileFormat;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.db.BankPaymentConfig;
|
||||
import com.axelor.apps.bankpayment.db.EbicsPartner;
|
||||
import com.axelor.apps.bankpayment.db.EbicsUser;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderFileFormatRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankOrderRepository;
|
||||
import com.axelor.apps.bankpayment.db.repo.EbicsPartnerRepository;
|
||||
import com.axelor.apps.bankpayment.ebics.service.EbicsService;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.bankpayment.service.app.AppBankPaymentService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.directdebit.BankOrderFile00800101Service;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.directdebit.BankOrderFile00800102Service;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.directdebit.BankOrderFile008Service;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.transfer.BankOrderFile00100102Service;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.transfer.BankOrderFile00100103Service;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.transfer.BankOrderFileAFB160ICTService;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.transfer.BankOrderFileAFB320XCTService;
|
||||
import com.axelor.apps.bankpayment.service.config.BankPaymentConfigService;
|
||||
import com.axelor.apps.bankpayment.service.invoice.payment.InvoicePaymentValidateServiceBankPayImpl;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.base.db.Currency;
|
||||
import com.axelor.apps.base.db.Partner;
|
||||
import com.axelor.apps.base.db.Sequence;
|
||||
import com.axelor.apps.base.service.BankDetailsService;
|
||||
import com.axelor.apps.base.service.administration.SequenceService;
|
||||
import com.axelor.apps.base.service.app.AppBaseService;
|
||||
import com.axelor.auth.db.User;
|
||||
import com.axelor.common.ObjectUtils;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.axelor.mail.db.repo.MailFollowerRepository;
|
||||
import com.axelor.meta.MetaFiles;
|
||||
import com.axelor.meta.schema.actions.ActionView;
|
||||
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BankOrderServiceImpl implements BankOrderService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
protected BankOrderRepository bankOrderRepo;
|
||||
protected InvoicePaymentRepository invoicePaymentRepo;
|
||||
protected BankOrderLineService bankOrderLineService;
|
||||
protected EbicsService ebicsService;
|
||||
protected InvoicePaymentCancelService invoicePaymentCancelService;
|
||||
protected BankPaymentConfigService bankPaymentConfigService;
|
||||
protected SequenceService sequenceService;
|
||||
protected BankOrderLineOriginService bankOrderLineOriginService;
|
||||
|
||||
@Inject
|
||||
public BankOrderServiceImpl(
|
||||
BankOrderRepository bankOrderRepo,
|
||||
InvoicePaymentRepository invoicePaymentRepo,
|
||||
BankOrderLineService bankOrderLineService,
|
||||
EbicsService ebicsService,
|
||||
InvoicePaymentCancelService invoicePaymentCancelService,
|
||||
BankPaymentConfigService bankPaymentConfigService,
|
||||
SequenceService sequenceService,
|
||||
BankOrderLineOriginService bankOrderLineOriginService) {
|
||||
|
||||
this.bankOrderRepo = bankOrderRepo;
|
||||
this.invoicePaymentRepo = invoicePaymentRepo;
|
||||
this.bankOrderLineService = bankOrderLineService;
|
||||
this.ebicsService = ebicsService;
|
||||
this.invoicePaymentCancelService = invoicePaymentCancelService;
|
||||
this.bankPaymentConfigService = bankPaymentConfigService;
|
||||
this.sequenceService = sequenceService;
|
||||
this.bankOrderLineOriginService = bankOrderLineOriginService;
|
||||
}
|
||||
|
||||
public void checkPreconditions(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
LocalDate brankOrderDate = bankOrder.getBankOrderDate();
|
||||
|
||||
if (brankOrderDate != null) {
|
||||
if (brankOrderDate.isBefore(LocalDate.now())) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_DATE));
|
||||
}
|
||||
} else {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_DATE_MISSING));
|
||||
}
|
||||
|
||||
if (bankOrder.getOrderTypeSelect() == 0) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_TYPE_MISSING));
|
||||
}
|
||||
if (bankOrder.getPartnerTypeSelect() == 0) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_PARTNER_TYPE_MISSING));
|
||||
}
|
||||
if (bankOrder.getPaymentMode() == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_PAYMENT_MODE_MISSING));
|
||||
}
|
||||
if (bankOrder.getSenderCompany() == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_COMPANY_MISSING));
|
||||
}
|
||||
if (bankOrder.getSenderBankDetails() == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_BANK_DETAILS_MISSING));
|
||||
}
|
||||
if (!bankOrder.getIsMultiCurrency() && bankOrder.getBankOrderCurrency() == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_CURRENCY_MISSING));
|
||||
}
|
||||
if (bankOrder.getSignatoryUser() == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_SIGNATORY_MISSING));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal computeBankOrderTotalAmount(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
BigDecimal bankOrderTotalAmount = BigDecimal.ZERO;
|
||||
|
||||
List<BankOrderLine> bankOrderLines = bankOrder.getBankOrderLineList();
|
||||
if (bankOrderLines != null) {
|
||||
for (BankOrderLine bankOrderLine : bankOrderLines) {
|
||||
BigDecimal amount = bankOrderLine.getBankOrderAmount();
|
||||
if (amount != null) {
|
||||
bankOrderTotalAmount = bankOrderTotalAmount.add(amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bankOrderTotalAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal computeCompanyCurrencyTotalAmount(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
BigDecimal companyCurrencyTotalAmount = BigDecimal.ZERO;
|
||||
|
||||
List<BankOrderLine> bankOrderLines = bankOrder.getBankOrderLineList();
|
||||
if (bankOrderLines != null) {
|
||||
for (BankOrderLine bankOrderLine : bankOrderLines) {
|
||||
BigDecimal amount = bankOrderLine.getCompanyCurrencyAmount();
|
||||
if (amount != null) {
|
||||
companyCurrencyTotalAmount = companyCurrencyTotalAmount.add(amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
return companyCurrencyTotalAmount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTotalAmounts(BankOrder bankOrder) throws AxelorException {
|
||||
if (bankOrder.getOrderTypeSelect().equals(BankOrderRepository.ORDER_TYPE_SEND_BANK_ORDER)) {
|
||||
bankOrder.setArithmeticTotal(bankOrder.getBankOrderTotalAmount());
|
||||
} else {
|
||||
bankOrder.setArithmeticTotal(this.computeBankOrderTotalAmount(bankOrder));
|
||||
}
|
||||
|
||||
if (!bankOrder.getIsMultiCurrency()) {
|
||||
bankOrder.setBankOrderTotalAmount(bankOrder.getArithmeticTotal());
|
||||
}
|
||||
|
||||
bankOrder.setCompanyCurrencyTotalAmount(this.computeCompanyCurrencyTotalAmount(bankOrder));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public BankOrder generateSequence(BankOrder bankOrder) throws AxelorException {
|
||||
if (bankOrder.getBankOrderSeq() == null) {
|
||||
|
||||
Sequence sequence = getSequence(bankOrder);
|
||||
setBankOrderSeq(bankOrder, sequence);
|
||||
bankOrderRepo.save(bankOrder);
|
||||
}
|
||||
return bankOrder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkLines(BankOrder bankOrder) throws AxelorException {
|
||||
List<BankOrderLine> bankOrderLines = bankOrder.getBankOrderLineList();
|
||||
if (bankOrderLines.isEmpty()) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINES_MISSING));
|
||||
} else {
|
||||
validateBankOrderLines(
|
||||
bankOrderLines, bankOrder.getOrderTypeSelect(), bankOrder.getArithmeticTotal());
|
||||
}
|
||||
}
|
||||
|
||||
public void validateBankOrderLines(
|
||||
List<BankOrderLine> bankOrderLines, int orderType, BigDecimal arithmeticTotal)
|
||||
throws AxelorException {
|
||||
BigDecimal totalAmount = BigDecimal.ZERO;
|
||||
for (BankOrderLine bankOrderLine : bankOrderLines) {
|
||||
|
||||
bankOrderLineService.checkPreconditions(bankOrderLine);
|
||||
totalAmount = totalAmount.add(bankOrderLine.getBankOrderAmount());
|
||||
bankOrderLineService.checkBankDetails(
|
||||
bankOrderLine.getReceiverBankDetails(), bankOrderLine.getBankOrder());
|
||||
}
|
||||
if (!totalAmount.equals(arithmeticTotal)) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_LINE_TOTAL_AMOUNT_INVALID));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validatePayment(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
List<InvoicePayment> invoicePaymentList = invoicePaymentRepo.findByBankOrder(bankOrder).fetch();
|
||||
|
||||
InvoicePaymentValidateServiceBankPayImpl invoicePaymentValidateServiceBankPayImpl =
|
||||
Beans.get(InvoicePaymentValidateServiceBankPayImpl.class);
|
||||
|
||||
for (InvoicePayment invoicePayment : invoicePaymentList) {
|
||||
if (invoicePayment != null
|
||||
&& invoicePayment.getStatusSelect() != InvoicePaymentRepository.STATUS_VALIDATED
|
||||
&& invoicePayment.getInvoice() != null) {
|
||||
|
||||
if (bankOrderLineOriginService.existBankOrderLineOrigin(
|
||||
bankOrder, invoicePayment.getInvoice())) {
|
||||
|
||||
invoicePaymentValidateServiceBankPayImpl.validateFromBankOrder(invoicePayment, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void cancelPayment(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
List<InvoicePayment> invoicePaymentList = invoicePaymentRepo.findByBankOrder(bankOrder).fetch();
|
||||
|
||||
for (InvoicePayment invoicePayment : invoicePaymentList) {
|
||||
if (invoicePayment != null
|
||||
&& invoicePayment.getStatusSelect() != InvoicePaymentRepository.STATUS_CANCELED) {
|
||||
invoicePaymentCancelService.cancel(invoicePayment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void confirm(BankOrder bankOrder)
|
||||
throws AxelorException, JAXBException, IOException, DatatypeConfigurationException {
|
||||
checkBankDetails(bankOrder.getSenderBankDetails(), bankOrder);
|
||||
|
||||
if (bankOrder.getGeneratedMetaFile() == null) {
|
||||
checkLines(bankOrder);
|
||||
}
|
||||
|
||||
setNbOfLines(bankOrder);
|
||||
|
||||
setSequenceOnBankOrderLines(bankOrder);
|
||||
|
||||
generateFile(bankOrder);
|
||||
|
||||
if (Beans.get(AppBankPaymentService.class).getAppBankPayment().getEnableEbicsModule()) {
|
||||
|
||||
bankOrder.setConfirmationDateTime(
|
||||
Beans.get(AppBaseService.class).getTodayDateTime().toLocalDateTime());
|
||||
bankOrder.setStatusSelect(BankOrderRepository.STATUS_AWAITING_SIGNATURE);
|
||||
makeEbicsUserFollow(bankOrder);
|
||||
|
||||
bankOrderRepo.save(bankOrder);
|
||||
} else {
|
||||
validate(bankOrder);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void sign(BankOrder bankOrder) {
|
||||
|
||||
// TODO
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void validate(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
bankOrder.setValidationDateTime(LocalDateTime.now());
|
||||
|
||||
bankOrder.setStatusSelect(BankOrderRepository.STATUS_VALIDATED);
|
||||
|
||||
if (bankPaymentConfigService
|
||||
.getBankPaymentConfig(bankOrder.getSenderCompany())
|
||||
.getGenerateMoveOnBankOrderValidation()) {
|
||||
validatePayment(bankOrder);
|
||||
}
|
||||
|
||||
bankOrderRepo.save(bankOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void realize(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
if (Beans.get(AppBankPaymentService.class).getAppBankPayment().getEnableEbicsModule()) {
|
||||
if (bankOrder.getSignatoryEbicsUser() == null) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get(IExceptionMessage.EBICS_MISSING_SIGNATORY_EBICS_USER));
|
||||
}
|
||||
if (bankOrder.getSignatoryEbicsUser().getEbicsPartner().getTransportEbicsUser() == null) {
|
||||
throw new AxelorException(
|
||||
bankOrder.getSignatoryEbicsUser().getEbicsPartner(),
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get(IExceptionMessage.EBICS_MISSING_USER_TRANSPORT));
|
||||
}
|
||||
|
||||
sendBankOrderFile(bankOrder);
|
||||
}
|
||||
realizeBankOrder(bankOrder);
|
||||
validatePayment(bankOrder);
|
||||
}
|
||||
|
||||
protected void sendBankOrderFile(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
File dataFileToSend = null;
|
||||
File signatureFileToSend = null;
|
||||
|
||||
if (bankOrder.getSignatoryEbicsUser().getEbicsPartner().getEbicsTypeSelect()
|
||||
== EbicsPartnerRepository.EBICS_TYPE_TS) {
|
||||
if (bankOrder.getSignedMetaFile() == null) {
|
||||
throw new AxelorException(
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_NOT_PROPERLY_SIGNED),
|
||||
TraceBackRepository.CATEGORY_NO_VALUE);
|
||||
}
|
||||
|
||||
signatureFileToSend = MetaFiles.getPath(bankOrder.getSignedMetaFile()).toFile();
|
||||
}
|
||||
dataFileToSend = MetaFiles.getPath(bankOrder.getGeneratedMetaFile()).toFile();
|
||||
|
||||
sendFile(bankOrder, dataFileToSend, signatureFileToSend);
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
protected void realizeBankOrder(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
AppBaseService appBaseService = Beans.get(AppBaseService.class);
|
||||
Beans.get(BankOrderMoveService.class).generateMoves(bankOrder);
|
||||
|
||||
bankOrder.setSendingDateTime(appBaseService.getTodayDateTime().toLocalDateTime());
|
||||
bankOrder.setStatusSelect(BankOrderRepository.STATUS_CARRIED_OUT);
|
||||
|
||||
if (Beans.get(AppBankPaymentService.class).getAppBankPayment().getEnableEbicsModule()) {
|
||||
bankOrder.setTestMode(bankOrder.getSignatoryEbicsUser().getEbicsPartner().getTestMode());
|
||||
}
|
||||
|
||||
bankOrderRepo.save(bankOrder);
|
||||
}
|
||||
|
||||
protected void sendFile(BankOrder bankOrder, File dataFileToSend, File signatureFileToSend)
|
||||
throws AxelorException {
|
||||
|
||||
PaymentMode paymentMode = bankOrder.getPaymentMode();
|
||||
|
||||
if (paymentMode != null && !paymentMode.getAutomaticTransmission()) {
|
||||
return;
|
||||
}
|
||||
|
||||
EbicsUser signatoryEbicsUser = bankOrder.getSignatoryEbicsUser();
|
||||
|
||||
ebicsService.sendFULRequest(
|
||||
signatoryEbicsUser.getEbicsPartner().getTransportEbicsUser(),
|
||||
signatoryEbicsUser,
|
||||
null,
|
||||
dataFileToSend,
|
||||
bankOrder.getBankOrderFileFormat(),
|
||||
signatureFileToSend);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSequenceOnBankOrderLines(BankOrder bankOrder) {
|
||||
|
||||
if (bankOrder.getBankOrderLineList() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String bankOrderSeq = bankOrder.getBankOrderSeq();
|
||||
|
||||
int counter = 1;
|
||||
|
||||
for (BankOrderLine bankOrderLine : bankOrder.getBankOrderLineList()) {
|
||||
|
||||
bankOrderLine.setCounter(counter);
|
||||
bankOrderLine.setSequence(bankOrderSeq + "-" + Integer.toString(counter++));
|
||||
}
|
||||
}
|
||||
|
||||
private void setNbOfLines(BankOrder bankOrder) {
|
||||
|
||||
if (bankOrder.getBankOrderLineList() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
bankOrder.setNbOfLines(bankOrder.getBankOrderLineList().size());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public void cancelBankOrder(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
bankOrder.setStatusSelect(BankOrderRepository.STATUS_CANCELED);
|
||||
|
||||
this.cancelPayment(bankOrder);
|
||||
|
||||
bankOrderRepo.save(bankOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public EbicsUser getDefaultEbicsUserFromBankDetails(BankDetails bankDetails) {
|
||||
EbicsPartner ebicsPartner =
|
||||
Beans.get(EbicsPartnerRepository.class)
|
||||
.all()
|
||||
.filter("? MEMBER OF self.bankDetailsSet", bankDetails)
|
||||
.fetchOne();
|
||||
if (ebicsPartner != null) {
|
||||
return ebicsPartner.getDefaultSignatoryEbicsUser();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createDomainForBankDetails(BankOrder bankOrder) {
|
||||
|
||||
String domain =
|
||||
Beans.get(BankDetailsService.class)
|
||||
.getActiveCompanyBankDetails(bankOrder.getSenderCompany());
|
||||
|
||||
// filter on the bank details identifier type from the bank order file
|
||||
// format
|
||||
if (bankOrder.getBankOrderFileFormat() != null) {
|
||||
String acceptedIdentifiers = bankOrder.getBankOrderFileFormat().getBankDetailsTypeSelect();
|
||||
if (acceptedIdentifiers != null && !acceptedIdentifiers.equals("")) {
|
||||
domain += " AND self.bank.bankDetailsTypeSelect IN (" + acceptedIdentifiers + ")";
|
||||
}
|
||||
}
|
||||
|
||||
// filter on the currency if it is set in file format and in the bankdetails
|
||||
Currency currency = bankOrder.getBankOrderCurrency();
|
||||
if (currency != null
|
||||
&& !bankOrder.getBankOrderFileFormat().getAllowOrderCurrDiffFromBankDetails()) {
|
||||
String fileFormatCurrencyId = currency.getId().toString();
|
||||
domain += " AND (self.currency IS NULL OR self.currency.id = " + fileFormatCurrencyId + ")";
|
||||
}
|
||||
return domain;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BankDetails getDefaultBankDetails(BankOrder bankOrder) {
|
||||
BankDetails candidateBankDetails;
|
||||
if (bankOrder.getSenderCompany() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
candidateBankDetails = bankOrder.getSenderCompany().getDefaultBankDetails();
|
||||
|
||||
try {
|
||||
this.checkBankDetails(candidateBankDetails, bankOrder);
|
||||
} catch (AxelorException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return candidateBankDetails;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkBankDetails(BankDetails bankDetails, BankOrder bankOrder)
|
||||
throws AxelorException {
|
||||
if (bankDetails == null) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_BANK_DETAILS_MISSING));
|
||||
}
|
||||
if (!bankDetails.getActive()) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_BANK_DETAILS_NOT_ACTIVE));
|
||||
}
|
||||
|
||||
if (bankOrder.getBankOrderFileFormat() != null) {
|
||||
if (!this.checkBankDetailsTypeCompatible(bankDetails, bankOrder.getBankOrderFileFormat())) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_BANK_DETAILS_TYPE_NOT_COMPATIBLE));
|
||||
}
|
||||
if (!bankOrder.getBankOrderFileFormat().getAllowOrderCurrDiffFromBankDetails()
|
||||
&& !this.checkBankDetailsCurrencyCompatible(bankDetails, bankOrder)) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_BANK_DETAILS_CURRENCY_NOT_COMPATIBLE));
|
||||
}
|
||||
}
|
||||
|
||||
if (bankOrder.getBankOrderFileFormat() != null
|
||||
&& bankOrder.getBankOrderFileFormat().getAllowOrderCurrDiffFromBankDetails()
|
||||
&& bankDetails.getCurrency() == null) {
|
||||
throw new AxelorException(
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_BANK_DETAILS_MISSING_CURRENCY),
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkBankDetailsTypeCompatible(
|
||||
BankDetails bankDetails, BankOrderFileFormat bankOrderFileFormat) {
|
||||
// filter on the bank details identifier type from the bank order file
|
||||
// format
|
||||
String acceptedIdentifiers = bankOrderFileFormat.getBankDetailsTypeSelect();
|
||||
if (acceptedIdentifiers != null && !acceptedIdentifiers.equals("")) {
|
||||
String[] identifiers = acceptedIdentifiers.replaceAll("\\s", "").split(",");
|
||||
int i = 0;
|
||||
while (i < identifiers.length
|
||||
&& bankDetails.getBank().getBankDetailsTypeSelect() != Integer.parseInt(identifiers[i])) {
|
||||
i++;
|
||||
}
|
||||
if (i == identifiers.length) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkBankDetailsCurrencyCompatible(BankDetails bankDetails, BankOrder bankOrder) {
|
||||
// filter on the currency if it is set in file format
|
||||
if (bankOrder.getBankOrderCurrency() != null) {
|
||||
if (bankDetails.getCurrency() != null
|
||||
&& bankDetails.getCurrency() != bankOrder.getBankOrderCurrency()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File generateFile(BankOrder bankOrder)
|
||||
throws JAXBException, IOException, AxelorException, DatatypeConfigurationException {
|
||||
|
||||
if (bankOrder.getBankOrderLineList() == null || bankOrder.getBankOrderLineList().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
bankOrder.setFileGenerationDateTime(LocalDateTime.now());
|
||||
|
||||
BankOrderFileFormat bankOrderFileFormat = bankOrder.getBankOrderFileFormat();
|
||||
|
||||
File file = null;
|
||||
|
||||
switch (bankOrderFileFormat.getOrderFileFormatSelect()) {
|
||||
case BankOrderFileFormatRepository.FILE_FORMAT_PAIN_001_001_02_SCT:
|
||||
file = new BankOrderFile00100102Service(bankOrder).generateFile();
|
||||
break;
|
||||
|
||||
case BankOrderFileFormatRepository.FILE_FORMAT_PAIN_001_001_03_SCT:
|
||||
file = new BankOrderFile00100103Service(bankOrder).generateFile();
|
||||
break;
|
||||
|
||||
case BankOrderFileFormatRepository.FILE_FORMAT_PAIN_XXX_CFONB320_XCT:
|
||||
file = new BankOrderFileAFB320XCTService(bankOrder).generateFile();
|
||||
break;
|
||||
|
||||
case BankOrderFileFormatRepository.FILE_FORMAT_PAIN_XXX_CFONB160_ICT:
|
||||
file = new BankOrderFileAFB160ICTService(bankOrder).generateFile();
|
||||
break;
|
||||
|
||||
case BankOrderFileFormatRepository.FILE_FORMAT_PAIN_008_001_01_SDD:
|
||||
file =
|
||||
new BankOrderFile00800101Service(bankOrder, BankOrderFile008Service.SEPA_TYPE_CORE)
|
||||
.generateFile();
|
||||
break;
|
||||
|
||||
case BankOrderFileFormatRepository.FILE_FORMAT_PAIN_008_001_01_SBB:
|
||||
file =
|
||||
new BankOrderFile00800101Service(bankOrder, BankOrderFile008Service.SEPA_TYPE_SBB)
|
||||
.generateFile();
|
||||
break;
|
||||
|
||||
case BankOrderFileFormatRepository.FILE_FORMAT_PAIN_008_001_02_SDD:
|
||||
file =
|
||||
new BankOrderFile00800102Service(bankOrder, BankOrderFile008Service.SEPA_TYPE_CORE)
|
||||
.generateFile();
|
||||
break;
|
||||
|
||||
case BankOrderFileFormatRepository.FILE_FORMAT_PAIN_008_001_02_SBB:
|
||||
file =
|
||||
new BankOrderFile00800102Service(bankOrder, BankOrderFile008Service.SEPA_TYPE_SBB)
|
||||
.generateFile();
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_FILE_UNKNOWN_FORMAT));
|
||||
}
|
||||
|
||||
if (file == null) {
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_ISSUE_DURING_FILE_GENERATION),
|
||||
bankOrder.getBankOrderSeq());
|
||||
}
|
||||
|
||||
MetaFiles metaFiles = Beans.get(MetaFiles.class);
|
||||
|
||||
try (InputStream is = new FileInputStream(file)) {
|
||||
metaFiles.attach(is, file.getName(), bankOrder);
|
||||
bankOrder.setGeneratedMetaFile(metaFiles.upload(file));
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
protected Sequence getSequence(BankOrder bankOrder) throws AxelorException {
|
||||
BankPaymentConfig bankPaymentConfig =
|
||||
Beans.get(BankPaymentConfigService.class)
|
||||
.getBankPaymentConfig(bankOrder.getSenderCompany());
|
||||
|
||||
switch (bankOrder.getOrderTypeSelect()) {
|
||||
case BankOrderRepository.ORDER_TYPE_SEPA_DIRECT_DEBIT:
|
||||
return bankPaymentConfigService.getSepaDirectDebitSequence(bankPaymentConfig);
|
||||
|
||||
case BankOrderRepository.ORDER_TYPE_SEPA_CREDIT_TRANSFER:
|
||||
return bankPaymentConfigService.getSepaCreditTransSequence(bankPaymentConfig);
|
||||
|
||||
case BankOrderRepository.ORDER_TYPE_INTERNATIONAL_DIRECT_DEBIT:
|
||||
return bankPaymentConfigService.getIntDirectDebitSequence(bankPaymentConfig);
|
||||
|
||||
case BankOrderRepository.ORDER_TYPE_INTERNATIONAL_CREDIT_TRANSFER:
|
||||
return bankPaymentConfigService.getIntCreditTransSequence(bankPaymentConfig);
|
||||
|
||||
case BankOrderRepository.ORDER_TYPE_NATIONAL_TREASURY_TRANSFER:
|
||||
return bankPaymentConfigService.getNatTreasuryTransSequence(bankPaymentConfig);
|
||||
|
||||
case BankOrderRepository.ORDER_TYPE_INTERNATIONAL_TREASURY_TRANSFER:
|
||||
return bankPaymentConfigService.getIntTreasuryTransSequence(bankPaymentConfig);
|
||||
|
||||
default:
|
||||
return bankPaymentConfigService.getOtherBankOrderSequence(bankPaymentConfig);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setBankOrderSeq(BankOrder bankOrder, Sequence sequence) throws AxelorException {
|
||||
bankOrder.setBankOrderSeq(
|
||||
(sequenceService.getSequenceNumber(sequence, bankOrder.getBankOrderDate())));
|
||||
|
||||
if (bankOrder.getBankOrderSeq() != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
throw new AxelorException(
|
||||
bankOrder,
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_COMPANY_NO_SEQUENCE),
|
||||
bankOrder.getSenderCompany().getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* The signatory ebics user will follow the bank order record
|
||||
*
|
||||
* @param bankOrder
|
||||
*/
|
||||
protected void makeEbicsUserFollow(BankOrder bankOrder) {
|
||||
EbicsUser ebicsUser = bankOrder.getSignatoryEbicsUser();
|
||||
if (ebicsUser != null) {
|
||||
User signatoryUser = ebicsUser.getAssociatedUser();
|
||||
Beans.get(MailFollowerRepository.class).follow(bankOrder, signatoryUser);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetReceivers(BankOrder bankOrder) {
|
||||
if (ObjectUtils.isEmpty(bankOrder.getBankOrderLineList())) {
|
||||
return;
|
||||
}
|
||||
|
||||
resetPartners(bankOrder);
|
||||
resetBankDetails(bankOrder);
|
||||
}
|
||||
|
||||
private void resetPartners(BankOrder bankOrder) {
|
||||
if (bankOrder.getPartnerTypeSelect() == BankOrderRepository.PARTNER_TYPE_COMPANY) {
|
||||
for (BankOrderLine bankOrderLine : bankOrder.getBankOrderLineList()) {
|
||||
bankOrderLine.setPartner(null);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for (BankOrderLine bankOrderLine : bankOrder.getBankOrderLineList()) {
|
||||
bankOrderLine.setReceiverCompany(null);
|
||||
Partner partner = bankOrderLine.getPartner();
|
||||
|
||||
if (partner == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean keep;
|
||||
|
||||
switch (bankOrder.getPartnerTypeSelect()) {
|
||||
case BankOrderRepository.PARTNER_TYPE_SUPPLIER:
|
||||
keep = partner.getIsSupplier();
|
||||
break;
|
||||
case BankOrderRepository.PARTNER_TYPE_EMPLOYEE:
|
||||
keep = partner.getIsEmployee();
|
||||
break;
|
||||
case BankOrderRepository.PARTNER_TYPE_CUSTOMER:
|
||||
keep = partner.getIsCustomer();
|
||||
break;
|
||||
default:
|
||||
keep = false;
|
||||
}
|
||||
|
||||
if (!keep) {
|
||||
bankOrderLine.setPartner(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resetBankDetails(BankOrder bankOrder) {
|
||||
for (BankOrderLine bankOrderLine : bankOrder.getBankOrderLineList()) {
|
||||
if (bankOrderLine.getReceiverBankDetails() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Collection<BankDetails> bankDetailsCollection;
|
||||
|
||||
if (bankOrderLine.getReceiverCompany() != null) {
|
||||
bankDetailsCollection = bankOrderLine.getReceiverCompany().getBankDetailsSet();
|
||||
} else if (bankOrderLine.getPartner() != null) {
|
||||
bankDetailsCollection = bankOrderLine.getPartner().getBankDetailsList();
|
||||
} else {
|
||||
bankDetailsCollection = Collections.emptyList();
|
||||
}
|
||||
|
||||
if (ObjectUtils.isEmpty(bankDetailsCollection)
|
||||
|| !bankDetailsCollection.contains(bankOrderLine.getReceiverBankDetails())) {
|
||||
bankOrderLine.setReceiverBankDetails(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionViewBuilder buildBankOrderLineView(
|
||||
String gridViewName, String formViewName, String viewDomain) {
|
||||
ActionViewBuilder actionViewBuilder =
|
||||
ActionView.define(I18n.get("Bank Order Lines"))
|
||||
.model(BankOrderLine.class.getName())
|
||||
.add("grid", gridViewName)
|
||||
.add("form", formViewName)
|
||||
.domain(viewDomain);
|
||||
return actionViewBuilder;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder.file;
|
||||
|
||||
import com.axelor.apps.account.db.PaymentMode;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderFileFormat;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.base.db.Address;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Currency;
|
||||
import com.axelor.apps.tool.file.FileTool;
|
||||
import com.axelor.apps.tool.xml.Marschaller;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.google.common.base.Strings;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class BankOrderFileService {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
protected static final String FILE_EXTENSION_XML = "xml";
|
||||
protected static final String FILE_EXTENSION_TXT = "txt";
|
||||
|
||||
protected PaymentMode paymentMode;
|
||||
protected BankOrderFileFormat bankOrderFileFormat;
|
||||
protected LocalDate bankOrderDate;
|
||||
protected BankDetails senderBankDetails;
|
||||
protected Company senderCompany;
|
||||
protected Currency bankOrderCurrency;
|
||||
protected BigDecimal bankOrderTotalAmount;
|
||||
protected BigDecimal arithmeticTotal;
|
||||
protected int nbOfLines;
|
||||
protected LocalDateTime generationDateTime;
|
||||
protected String bankOrderSeq;
|
||||
protected boolean isMultiDates;
|
||||
protected boolean isMultiCurrencies;
|
||||
|
||||
protected List<BankOrderLine> bankOrderLineList;
|
||||
protected Object fileToCreate;
|
||||
protected String context;
|
||||
protected String fileExtension;
|
||||
|
||||
public BankOrderFileService(BankOrder bankOrder) {
|
||||
|
||||
this.paymentMode = bankOrder.getPaymentMode();
|
||||
this.bankOrderFileFormat = bankOrder.getBankOrderFileFormat();
|
||||
this.bankOrderDate = bankOrder.getBankOrderDate();
|
||||
this.senderBankDetails = bankOrder.getSenderBankDetails();
|
||||
this.senderCompany = bankOrder.getSenderCompany();
|
||||
this.bankOrderCurrency = bankOrder.getBankOrderCurrency();
|
||||
this.bankOrderTotalAmount = bankOrder.getBankOrderTotalAmount();
|
||||
this.arithmeticTotal = bankOrder.getArithmeticTotal();
|
||||
this.nbOfLines = bankOrder.getNbOfLines();
|
||||
this.generationDateTime = bankOrder.getFileGenerationDateTime();
|
||||
this.bankOrderSeq = bankOrder.getBankOrderSeq();
|
||||
this.bankOrderLineList = bankOrder.getBankOrderLineList();
|
||||
this.isMultiDates = bankOrder.getIsMultiDate();
|
||||
this.isMultiCurrencies = bankOrder.getIsMultiCurrency();
|
||||
}
|
||||
|
||||
protected String getSenderAddress() throws AxelorException {
|
||||
|
||||
Address senderAddress = this.senderCompany.getAddress();
|
||||
|
||||
if (senderAddress == null || Strings.isNullOrEmpty(senderAddress.getFullName())) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_FILE_NO_SENDER_ADDRESS),
|
||||
senderCompany.getName());
|
||||
}
|
||||
|
||||
return senderAddress.getFullName();
|
||||
}
|
||||
|
||||
protected String getFolderPath() throws AxelorException {
|
||||
|
||||
String folderPath = paymentMode.getBankOrderExportFolderPath();
|
||||
|
||||
if (Strings.isNullOrEmpty(folderPath)) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_FILE_NO_FOLDER_PATH),
|
||||
paymentMode.getName());
|
||||
}
|
||||
|
||||
return folderPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the order XML file
|
||||
*
|
||||
* @throws AxelorException
|
||||
* @throws IOException
|
||||
* @throws JAXBException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public File generateFile()
|
||||
throws JAXBException, IOException, AxelorException, DatatypeConfigurationException {
|
||||
|
||||
switch (fileExtension) {
|
||||
case FILE_EXTENSION_XML:
|
||||
return Marschaller.marschalFile(
|
||||
fileToCreate, context, this.getFolderPath(), this.computeFileName());
|
||||
|
||||
case FILE_EXTENSION_TXT:
|
||||
try {
|
||||
return FileTool.writer(
|
||||
this.getFolderPath(), this.computeFileName(), (List<String>) fileToCreate);
|
||||
} catch (IOException e) {
|
||||
throw new AxelorException(
|
||||
e.getCause(),
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(com.axelor.apps.account.exception.IExceptionMessage.CFONB_EXPORT_2),
|
||||
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
|
||||
e);
|
||||
}
|
||||
|
||||
default:
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_INCONSISTENCY,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_FILE_UNKNOWN_FORMAT),
|
||||
paymentMode.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public String computeFileName() {
|
||||
|
||||
return String.format(
|
||||
"%s%s.%s",
|
||||
bankOrderFileFormat.getOrderFileFormatSelect(),
|
||||
generationDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")),
|
||||
fileExtension);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,662 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder.file.directdebit;
|
||||
|
||||
import com.axelor.apps.account.db.Umr;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.bankpayment.service.config.BankPaymentConfigService;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.AccountIdentification3Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.BranchAndFinancialInstitutionIdentification3;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.CashAccount7;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.ChargeBearerType1Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.CurrencyAndAmount;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.DirectDebitTransaction1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.DirectDebitTransactionInformation1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.Document;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.FinancialInstitutionIdentification5Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.GenericIdentification3;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.GenericIdentification4;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.GroupHeader1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.Grouping1Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.LocalInstrument1Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.MandateRelatedInformation1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.ObjectFactory;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.Pain00800101;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.Party2Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.PartyIdentification8;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.PaymentIdentification1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.PaymentInstructionInformation2;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.PaymentMethod2Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.PaymentTypeInformation2;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.PersonIdentification3;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.RemittanceInformation1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.SequenceType1Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.ServiceLevel2Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01.ServiceLevel3Choice;
|
||||
import com.axelor.apps.base.db.Bank;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import javax.xml.datatype.DatatypeFactory;
|
||||
|
||||
public class BankOrderFile00800101Service extends BankOrderFile008Service {
|
||||
|
||||
protected ObjectFactory factory;
|
||||
protected String sepaType;
|
||||
|
||||
@Inject
|
||||
public BankOrderFile00800101Service(BankOrder bankOrder, String sepaType) {
|
||||
super(bankOrder);
|
||||
|
||||
context = "com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_01";
|
||||
|
||||
factory = new ObjectFactory();
|
||||
this.sepaType = sepaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the XML SEPA Direct Debit file (pain.008.001.01)
|
||||
*
|
||||
* @return the SEPA Direct Debit file (pain.008.001.01)
|
||||
* @throws JAXBException
|
||||
* @throws IOException
|
||||
* @throws AxelorException
|
||||
* @throws DatatypeConfigurationException
|
||||
*/
|
||||
@Override
|
||||
public File generateFile()
|
||||
throws JAXBException, IOException, AxelorException, DatatypeConfigurationException {
|
||||
// Creditor
|
||||
PartyIdentification8 creditor = factory.createPartyIdentification8();
|
||||
creditor.setNm(senderBankDetails.getOwnerName());
|
||||
|
||||
/*
|
||||
* Hierarchy of a XML file
|
||||
*
|
||||
* GroupHeader : This building block is mandatory and present once.
|
||||
* It contains elements such as Message Identification,
|
||||
* Creation Date And Time, Grouping indicator.
|
||||
* Payment Information : This building block is mandatory and repetitive.
|
||||
* It contains, among other things, elements related
|
||||
* to the Credit side of the transaction, such as
|
||||
* Creditor and Payment Type Information.
|
||||
* Direct Debit Transaction Information : This building block is mandatory and repetitive.
|
||||
* It contains, among other things, elements related
|
||||
* to the debit side of the transaction, such as
|
||||
* Debtor and Remittance Information Rules.
|
||||
*
|
||||
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
* <Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.01">
|
||||
* <pain.008.001.01>
|
||||
* <GrpHdr> <-- occ : 1..1
|
||||
* </GrpHdr>
|
||||
* <PmtInf> <-- occ : 1..n
|
||||
* <DrctDbtTxInf> <-- occ : 1..n
|
||||
* </DrctDbtTxInf>
|
||||
* </PmtInf>
|
||||
* </pain.008.001.01>
|
||||
* </Document>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Document, <Document> tag
|
||||
*/
|
||||
Document document = factory.createDocument();
|
||||
|
||||
/*
|
||||
* pain.008.001.01, <pain.008.001.01> tag
|
||||
*/
|
||||
Pain00800101 pain00800101 = factory.createPain00800101();
|
||||
document.setPain00800101(pain00800101);
|
||||
|
||||
/*
|
||||
* Group Header, <GrpHdr> tag
|
||||
* Set of characteristics shared by all individual transactions included in the message.
|
||||
*/
|
||||
GroupHeader1 groupHeader = factory.createGroupHeader1();
|
||||
createGrpHdr(groupHeader, creditor);
|
||||
pain00800101.setGrpHdr(groupHeader);
|
||||
|
||||
/*
|
||||
* Payment Information, <PmtInf> tag
|
||||
* Does not need to set the List<PaymentInstructionInformation2> to the pain00800101 object (see doc).
|
||||
*/
|
||||
createPmtInf(pain00800101.getPmtInf(), creditor);
|
||||
|
||||
fileToCreate = factory.createDocument(document);
|
||||
return super.generateFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the GroupHeader part ({@code <GrpHdr>} tag) of the file, into the provided {@link
|
||||
* GroupHeader1} object
|
||||
*
|
||||
* @param groupHeader the {@link GroupHeader1} to build
|
||||
* @param creditor the creditor of the SEPA Direct Debit file
|
||||
* @throws DatatypeConfigurationException
|
||||
*/
|
||||
protected void createGrpHdr(GroupHeader1 groupHeader, PartyIdentification8 creditor)
|
||||
throws DatatypeConfigurationException {
|
||||
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
|
||||
|
||||
/*
|
||||
* Message Identification (mandatory)
|
||||
* Point to point reference assigned by the instructing party and sent to the next party in the chain to unambiguously identify the message.
|
||||
*/
|
||||
groupHeader.setMsgId(bankOrderSeq);
|
||||
|
||||
/*
|
||||
* Creation Date Time (mandatory)
|
||||
* Date and time at which a (group of) payment instruction(s) was created by the instructing party.
|
||||
*
|
||||
* Format : YYYY-MM-DDThh:mm:ss
|
||||
* Example : <CreDtTm>2009-12-02T08:35:30</CreDtTm>
|
||||
*/
|
||||
groupHeader.setCreDtTm(
|
||||
datatypeFactory.newXMLGregorianCalendar(
|
||||
generationDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))));
|
||||
|
||||
/*
|
||||
* Batch Booking (optional)
|
||||
* Identifies whether a single entry per individual transaction or a batch entry for the sum of the amounts of all transactions in the message is required.
|
||||
*
|
||||
* Usage : Recommended "true". If absent then default "true".
|
||||
*
|
||||
* 'true' if : Identifies that a batch entry for the sum of the amounts of all
|
||||
* transactions in a Payment Information Block is required.
|
||||
* (one credit for all transactions in a Payment Information Block)
|
||||
* 'false' if : Identifies that a single entry for each of the transactions
|
||||
* in a message is required.
|
||||
*
|
||||
*/
|
||||
groupHeader.setBtchBookg(true);
|
||||
|
||||
/*
|
||||
* Number Of Transactions (mandatory)
|
||||
* Number of individual transactions contained in the message.
|
||||
*/
|
||||
groupHeader.setNbOfTxs(Integer.toString(nbOfLines));
|
||||
|
||||
/*
|
||||
* Pas documenté dans le fichier, repris du fichier BankOrderFile00100103Service.java
|
||||
*/
|
||||
groupHeader.setCtrlSum(arithmeticTotal);
|
||||
|
||||
/*
|
||||
* Grouping (mandatory)
|
||||
* Indicates whether common accounting information in the transaction is included once for all transactions or repeated for each single transaction.
|
||||
*/
|
||||
groupHeader.setGrpg(Grouping1Code.MIXD); // TO CHECK
|
||||
|
||||
/*
|
||||
* Initiating Party (mandatory)
|
||||
* Party initiating the payment. In the direct debit context, this can be the creditor, or the party that initiates the payment on behalf of the creditor.
|
||||
*/
|
||||
groupHeader.setInitgPty(creditor);
|
||||
|
||||
/*
|
||||
* Pas documenté dans le fichier
|
||||
*/
|
||||
// groupHeader.setFwdgAgt(???);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the PaymentInformation part ({@code <PmtInf>} tag) of the file, and adds it into the
|
||||
* provided {@link PaymentInstructionInformation2} list
|
||||
*
|
||||
* @param paymentInstructionInformationList the list to add the {@link
|
||||
* PaymentInstructionInformation2} objects into
|
||||
* @param creditor the creditor of the SEPA Direct Debit file
|
||||
* @throws DatatypeConfigurationException
|
||||
*/
|
||||
protected void createPmtInf(
|
||||
List<PaymentInstructionInformation2> paymentInstructionInformationList,
|
||||
PartyIdentification8 creditor)
|
||||
throws AxelorException, DatatypeConfigurationException {
|
||||
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
|
||||
|
||||
/*
|
||||
* Payment Information (mandatory)
|
||||
* Set of characteristics that apply to the credit side of the payment transactions included in the direct debit transaction initiation.
|
||||
*/
|
||||
PaymentInstructionInformation2 paymentInstructionInformation2 =
|
||||
factory.createPaymentInstructionInformation2();
|
||||
paymentInstructionInformationList.add(paymentInstructionInformation2);
|
||||
|
||||
/*
|
||||
* Payment Information Identification (optional)
|
||||
* Reference assigned by a sending party to unambiguously identify the payment information block within the message.
|
||||
*/
|
||||
paymentInstructionInformation2.setPmtInfId(bankOrderSeq);
|
||||
|
||||
/*
|
||||
* Payment Method (mandatory, always 'DD')
|
||||
* Specifies the means of payment that will be used to move the amount of money.
|
||||
*/
|
||||
paymentInstructionInformation2.setPmtMtd(PaymentMethod2Code.DD);
|
||||
|
||||
/*
|
||||
* Payment Type Information (mandatory)
|
||||
* Set of elements that further specifies the type of transaction.
|
||||
*/
|
||||
PaymentTypeInformation2 paymentTypeInformation2 = factory.createPaymentTypeInformation2();
|
||||
paymentInstructionInformation2.setPmtTpInf(paymentTypeInformation2);
|
||||
|
||||
/*
|
||||
* ServiceLevel (mandatory)
|
||||
* Agreement under which or rules under which the transaction should be processed.
|
||||
*/
|
||||
ServiceLevel3Choice serviceLevel3Choice = factory.createServiceLevel3Choice();
|
||||
paymentTypeInformation2.setSvcLvl(serviceLevel3Choice);
|
||||
/*
|
||||
* Code (mandatory, always 'SEPA')
|
||||
* Identification of a pre-agreed level of service between the parties in a coded form.
|
||||
*/
|
||||
serviceLevel3Choice.setCd(ServiceLevel2Code.SEPA);
|
||||
|
||||
/*
|
||||
* Local Instrument (mandatory)
|
||||
* User community specific instrument.
|
||||
*/
|
||||
LocalInstrument1Choice localInstrument1Choice = factory.createLocalInstrument1Choice();
|
||||
/*
|
||||
* Code (mandatory)
|
||||
*
|
||||
* Format : either 'CORE' or 'B2B'
|
||||
* Rule : The mixing of Core Direct Debits and Business-to-Business Direct Debits is not
|
||||
* allowed in the same message.
|
||||
*/
|
||||
switch (sepaType) {
|
||||
case SEPA_TYPE_CORE:
|
||||
localInstrument1Choice.setCd(SEPA_TYPE_CORE);
|
||||
break;
|
||||
case SEPA_TYPE_SBB:
|
||||
localInstrument1Choice.setCd(SEPA_TYPE_SBB);
|
||||
break;
|
||||
default:
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_FILE_UNKNOWN_SEPA_TYPE));
|
||||
}
|
||||
paymentTypeInformation2.setLclInstrm(localInstrument1Choice);
|
||||
|
||||
/*
|
||||
* Sequence Type (mandatory) // TO CHECK
|
||||
* Identifies the direct debit sequence, e.g. first, recurrent, final or one-off.
|
||||
*
|
||||
* Either one of the following values.
|
||||
* CODE Name Definition
|
||||
* ------------------------------------------------------------------------------------
|
||||
* FRST First First collection of a series of direct debit instructions.
|
||||
* RCUR Recurrent Direct debit instruction where the debtor's authorisation is used for
|
||||
* regular direct debit transactions initiated by the creditor.
|
||||
* FNAL Final Final collection of a series of direct debit instructions.
|
||||
* OOFF One Off Direct debit instruction where the debtor's authorisation is used to
|
||||
* initiate one single direct debit transaction.
|
||||
*/
|
||||
paymentTypeInformation2.setSeqTp(SequenceType1Code.FRST);
|
||||
|
||||
/*
|
||||
* Category Purpose (optional)
|
||||
* Specifies the purpose of the payment based on a set of pre-defined categories.
|
||||
*
|
||||
* iso20022.org -> 'PaymentCategoryPurpose1Code' for all codes available and definitions.
|
||||
* Rule : The usage and impact of these codes is to be agreed with your bank.
|
||||
*/
|
||||
// paymentTypeInformation2.setCtgyPurp(PaymentCategoryPurpose1Code.CASH);
|
||||
|
||||
/*
|
||||
* Requested Collection Date (mandatory)
|
||||
* Date at which the creditor requests the amount of money to be collected from the debtor.
|
||||
*
|
||||
* Format : YYYY-MM-DD
|
||||
* Usage : The minimum delay between sending date and requested collection date is depending
|
||||
* on the type of direct debit (B2B or CORE) and on the sequence type (FRST, OOFF,
|
||||
* RCUR, FNAL).
|
||||
*/
|
||||
paymentInstructionInformation2.setReqdColltnDt(
|
||||
datatypeFactory.newXMLGregorianCalendar(
|
||||
bankOrderDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
|
||||
|
||||
/*
|
||||
* Creditor (mandatory)
|
||||
* Party to which an amount of money is due.
|
||||
*/
|
||||
paymentInstructionInformation2.setCdtr(creditor);
|
||||
|
||||
/*
|
||||
* Creditor Account (mandatory)
|
||||
* Unambiguous identification of the account of the creditor to which a credit entry will be posted as a result of the payment transaction.
|
||||
*/
|
||||
AccountIdentification3Choice accountIdentification3Choice =
|
||||
factory.createAccountIdentification3Choice();
|
||||
accountIdentification3Choice.setIBAN(senderBankDetails.getIban());
|
||||
CashAccount7 cashAccount7 = factory.createCashAccount7();
|
||||
cashAccount7.setId(accountIdentification3Choice);
|
||||
paymentInstructionInformation2.setCdtrAcct(cashAccount7);
|
||||
|
||||
/*
|
||||
* Creditor Agent (mandatory)
|
||||
* Financial institution servicing an account for the creditor.
|
||||
*
|
||||
* Note : The Bank Identifier Code (BIC) is composed of 8 or 11 characters, of which only the
|
||||
* first 8 characters are significant.
|
||||
*/
|
||||
FinancialInstitutionIdentification5Choice financialInstitutionIdentification5Choice =
|
||||
factory.createFinancialInstitutionIdentification5Choice();
|
||||
financialInstitutionIdentification5Choice.setBIC(senderBankDetails.getBank().getCode()); // BIC
|
||||
BranchAndFinancialInstitutionIdentification3 branchAndFinancialInstitutionIdentification3 =
|
||||
factory.createBranchAndFinancialInstitutionIdentification3();
|
||||
branchAndFinancialInstitutionIdentification3.setFinInstnId(
|
||||
financialInstitutionIdentification5Choice);
|
||||
paymentInstructionInformation2.setCdtrAgt(branchAndFinancialInstitutionIdentification3);
|
||||
|
||||
/*
|
||||
* Ultimate Creditor (optional)
|
||||
* Ultimate party to which an amount of money is due. Ultimate Creditor is only to be used if different from Creditor.
|
||||
*/
|
||||
// paymentInstructionInformation2.setUltmtCdtr();
|
||||
|
||||
/*
|
||||
* Charge Bearer (mandatory) // TO CHECK : option dans la vue BankOrder
|
||||
* Specifies which party/parties will bear the charges associated with the processing of the payment transaction.
|
||||
*
|
||||
* CODE Name Description
|
||||
* ----------------------------------------------------------------------------------------
|
||||
* DEBT BorneByDebtor All transaction charges are to be borne by the debtor
|
||||
* CRED BorneByCreditor All transaction charges are to be borne by the creditor
|
||||
* SHAR Shared In a direct debit context, means that transaction charges on
|
||||
* the sender side are to be borne by the creditor, transaction
|
||||
* charges on the receiver side are to be borne by the debtor.
|
||||
* SLEV FollowingServiceLevel Charges are to be applied following the rules agreed in the
|
||||
* service level and/or scheme.
|
||||
*/
|
||||
paymentInstructionInformation2.setChrgBr(ChargeBearerType1Code.SLEV);
|
||||
|
||||
/*
|
||||
* Direct Debit Transaction Information, <DrctDbtTxInf> tag
|
||||
* Does not need to set the List<DirectDebitTransactionInformation1> to the paymentInstructionInformation2 object (see doc)
|
||||
*/
|
||||
createDrctDbtTxInf(paymentInstructionInformation2.getDrctDbtTxInf(), creditor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the DirectDebitTransactionInformation part ({@code <DrctDbtTxInf>} tag) of the file, and
|
||||
* adds it into the provided {@link DirectDebitTransactionInformation1} list
|
||||
*
|
||||
* @param directDebitTransactionInformation1List the list to add the {@link
|
||||
* DirectDebitTransactionInformation1} objects into
|
||||
* @param creditor the creditor of the SEPA Direct Debit file
|
||||
* @throws DatatypeConfigurationException
|
||||
* @throws AxelorException
|
||||
*/
|
||||
protected void createDrctDbtTxInf(
|
||||
List<DirectDebitTransactionInformation1> directDebitTransactionInformation1List,
|
||||
PartyIdentification8 creditor)
|
||||
throws DatatypeConfigurationException, AxelorException {
|
||||
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
|
||||
|
||||
for (BankOrderLine bankOrderLine : bankOrderLineList) {
|
||||
|
||||
BankDetails receiverBankDetails = bankOrderLine.getReceiverBankDetails();
|
||||
Umr receiverUmr = bankOrderLine.getPartner().getActiveUmr();
|
||||
|
||||
if (receiverUmr == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.DIRECT_DEBIT_MISSING_PARTNER_ACTIVE_UMR));
|
||||
}
|
||||
|
||||
/*
|
||||
* Direct Debit Transaction Information (mandatory)
|
||||
* Set of elements providing information specific to the individual transaction(s) included in the message.
|
||||
*/
|
||||
DirectDebitTransactionInformation1 directDebitTransactionInformation1 =
|
||||
factory.createDirectDebitTransactionInformation1();
|
||||
directDebitTransactionInformation1List.add(directDebitTransactionInformation1);
|
||||
|
||||
/*
|
||||
* Payment Identification (mandatory)
|
||||
* Set of elements to reference a payment instruction.
|
||||
*/
|
||||
PaymentIdentification1 paymentIdentification1 = factory.createPaymentIdentification1();
|
||||
directDebitTransactionInformation1.setPmtId(paymentIdentification1);
|
||||
/*
|
||||
* Instruction Identification (optional)
|
||||
* The Instruction Identification is a unique reference assigned by the Initiator to unambiguously identify the transaction.
|
||||
* It can be used in status messages related to the transaction.
|
||||
*/
|
||||
// paymentIdentification1.setInstrId();
|
||||
/*
|
||||
* End To End Identification (mandatory)
|
||||
* Unique identification assigned by the initiating party to unumbiguously identify the transaction.
|
||||
* This identification is passed on, unchanged, throughout the entire end-to-end chain.
|
||||
*/
|
||||
paymentIdentification1.setEndToEndId(bankOrderLine.getSequence());
|
||||
|
||||
/*
|
||||
* Instructed Amount (mandatory)
|
||||
* Amount of the direct debit, expressed in euro.
|
||||
*
|
||||
* Format : Max. 11 digits of which 2 for the fractional part.
|
||||
* Decimal separator is "."
|
||||
* Currency "EUR" is explicit, and included in the XML tag.
|
||||
* Usage : Amount must be between 0.01 and 999999999.99
|
||||
*/
|
||||
CurrencyAndAmount currencyAndAmount = factory.createCurrencyAndAmount();
|
||||
currencyAndAmount.setCcy(CURRENCY_CODE);
|
||||
currencyAndAmount.setValue(bankOrderLine.getBankOrderAmount());
|
||||
directDebitTransactionInformation1.setInstdAmt(currencyAndAmount);
|
||||
|
||||
/*
|
||||
* Direct Debit Transaction (mandatory)
|
||||
* Set of elements providing information specific to the direct debit mandate.
|
||||
*/
|
||||
DirectDebitTransaction1 directDebitTransaction1 = factory.createDirectDebitTransaction1();
|
||||
directDebitTransactionInformation1.setDrctDbtTx(directDebitTransaction1);
|
||||
/*
|
||||
* Mandate Related Information (mandatory)
|
||||
* Set of elements used to provide further details related to a direct debit mandate signed between the creditor and the debtor.
|
||||
*/
|
||||
MandateRelatedInformation1 mandateRelatedInformation1 =
|
||||
factory.createMandateRelatedInformation1();
|
||||
directDebitTransaction1.setMndtRltdInf(mandateRelatedInformation1);
|
||||
/*
|
||||
* Mandate Identification (mandatory)
|
||||
* Reference of the direct debit mandate that has been signed between by the debtor and the creditor.
|
||||
*/
|
||||
mandateRelatedInformation1.setMndtId(receiverUmr.getUmrNumber());
|
||||
/*
|
||||
* Date of Signature (mandatory)
|
||||
* Date on which the direct debit mandate has been signed by the debtor.
|
||||
*
|
||||
* Format : YYYY-MM-DD
|
||||
*/
|
||||
mandateRelatedInformation1.setDtOfSgntr(
|
||||
datatypeFactory.newXMLGregorianCalendar(
|
||||
receiverUmr
|
||||
.getMandateSignatureDate()
|
||||
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
|
||||
/*
|
||||
* Amendment Indicator (optional)
|
||||
* Indicator notifying whether the underlying mandate is amended or not.
|
||||
*
|
||||
* Usage : - If not present, considered as "false".
|
||||
* - If true, 'Amendment Information Details' is mandatory.
|
||||
*
|
||||
* 'true' if : The mandate is amended or migrated from Dom'80.
|
||||
* 'false' if : The mandate is not amended.
|
||||
*/
|
||||
// mandateRelatedInformation1.setAmdmntInd(???);
|
||||
/*
|
||||
* Amendment Info Details (optional)
|
||||
* List of direct debit mandate elements that have been modified.
|
||||
*/
|
||||
// AmendmentInformationDetails1 amendmentInformationDetails1 =
|
||||
// factory.createAmendmentInformationDetails1();
|
||||
// mandateRelatedInformation1.setAmdmntInfDtls(amendmentInformationDetails1);
|
||||
// amendmentInformationDetails1.setOrgnlMndtId(???);
|
||||
// amendmentInformationDetails1.setOrgnlCdtrSchmeId(???);
|
||||
// amendmentInformationDetails1.setOrgnlDbtrAcct(???);
|
||||
// amendmentInformationDetails1.setOrgnlDbtrAgt(???);
|
||||
/*
|
||||
* Electronic Signature (optional)
|
||||
* Digital signature as provided by the creditor.
|
||||
*
|
||||
* Usage : - If the direct debit is based on an electronic mandate, this data
|
||||
* element must contain the reference of the Mandate Acceptance Report.
|
||||
* - If the direct debit is based on a paper mandate, this data element
|
||||
* is not allowed.
|
||||
*/
|
||||
// mandateRelatedInformation1.setElctrncSgntr(???);
|
||||
/*
|
||||
* Creditor Scheme Identification (mandatory)
|
||||
* Credit party that signs the direct debit mandate.
|
||||
*/
|
||||
PartyIdentification8 creditorSchemeId = factory.createPartyIdentification8();
|
||||
directDebitTransaction1.setCdtrSchmeId(creditorSchemeId);
|
||||
Party2Choice party2Choice = factory.createParty2Choice();
|
||||
creditorSchemeId.setId(party2Choice);
|
||||
PersonIdentification3 personIdentification3 = factory.createPersonIdentification3();
|
||||
party2Choice.getPrvtId().add(personIdentification3);
|
||||
GenericIdentification4 genericIdentification4 = factory.createGenericIdentification4();
|
||||
personIdentification3.setOthrId(genericIdentification4);
|
||||
genericIdentification4.setId(
|
||||
Beans.get(BankPaymentConfigService.class)
|
||||
.getIcsNumber(senderCompany.getBankPaymentConfig()));
|
||||
genericIdentification4.setIdTp("SEPA");
|
||||
|
||||
/*
|
||||
* Ultimate Creditor (optional)
|
||||
* Ultimate party to which an amount of money is due. Ultimate Creditor is only to be used if different from Creditor.
|
||||
*/
|
||||
// directDebitTransaction1.setUltmtCdtr();
|
||||
|
||||
/*
|
||||
* Debtor Agent (mandatory)
|
||||
* Financial institution servicing an account for the debtor.
|
||||
*/
|
||||
BranchAndFinancialInstitutionIdentification3 branchAndFinancialInstitutionIdentification3 =
|
||||
factory.createBranchAndFinancialInstitutionIdentification3();
|
||||
FinancialInstitutionIdentification5Choice financialInstitutionIdentification5Choice =
|
||||
factory.createFinancialInstitutionIdentification5Choice();
|
||||
|
||||
fillBic(financialInstitutionIdentification5Choice, receiverBankDetails.getBank()); // BIC
|
||||
|
||||
branchAndFinancialInstitutionIdentification3.setFinInstnId(
|
||||
financialInstitutionIdentification5Choice);
|
||||
directDebitTransactionInformation1.setDbtrAgt(branchAndFinancialInstitutionIdentification3);
|
||||
|
||||
/*
|
||||
* Debtor (mandatory)
|
||||
* Party that owes an amount of money to the (ultimate) creditor.
|
||||
*/
|
||||
PartyIdentification8 debtor = factory.createPartyIdentification8();
|
||||
debtor.setNm(receiverBankDetails.getOwnerName());
|
||||
directDebitTransactionInformation1.setDbtr(debtor);
|
||||
|
||||
/*
|
||||
* Debtor Account (mandatory)
|
||||
* Identification of the account of the debtor to which a debit entry will be made to execute the transfer.
|
||||
*/
|
||||
AccountIdentification3Choice accountIdentification3Choice =
|
||||
factory.createAccountIdentification3Choice();
|
||||
accountIdentification3Choice.setIBAN(receiverBankDetails.getIban());
|
||||
CashAccount7 cashAccount7 = factory.createCashAccount7();
|
||||
cashAccount7.setId(accountIdentification3Choice);
|
||||
directDebitTransactionInformation1.setDbtrAcct(cashAccount7);
|
||||
|
||||
/*
|
||||
* Ultimate Debtor (optional)
|
||||
* Ultimate party that owes an amount of money to the (ultimate) creditor. Ultimate Debtor is only to be used if different from Debtor.
|
||||
*/
|
||||
// directDebitTransactionInformation1.setUltmtDbtr(???);
|
||||
|
||||
/*
|
||||
* Purpose (optional)
|
||||
* Underlying reason for the payment transaction.
|
||||
* Purpose is used by the Debtor to provide information to the Creditor, concerning thenature of the payment transaction.
|
||||
* It is not used for processing by any of the banks involved.
|
||||
*/
|
||||
// Purpose1Choice purpose1Choice = factory.createPurpose1Choice();
|
||||
// directDebitTransactionInformation1.setPurp(purpose1Choice);
|
||||
/*
|
||||
* Code (mandatory)
|
||||
* Specifies the underlying reason of the payment transaction.
|
||||
*/
|
||||
// purpose1Choice.setCd(???);
|
||||
|
||||
/*
|
||||
* Remittance Information (optional)
|
||||
* Information that enables the matching, ie, reconciliation, of a payment with the items that the payment
|
||||
* is intended to settle, eg, commercial invoices in an account receivable system.
|
||||
*
|
||||
* Usage : Either Structured or Unstructured, but not both.
|
||||
*/
|
||||
RemittanceInformation1 remittanceInformation1 = factory.createRemittanceInformation1();
|
||||
directDebitTransactionInformation1.setRmtInf(remittanceInformation1);
|
||||
/*
|
||||
* Unstructured (choice 1 of 2)
|
||||
* Information supplied to enable the matching of an entry with the items that the transfer is intended
|
||||
* to settle, eg, commercial invoices in an accounts' receivable system in an unstructured form.
|
||||
*/
|
||||
remittanceInformation1.getUstrd().add(bankOrderLine.getReceiverReference());
|
||||
|
||||
/*
|
||||
* Structured (choice 2 of 2)
|
||||
* Information supplied to enable the matching of an entry with the items that the transfer is intended
|
||||
* to settle, eg, commercial invoices in an accounts' receivable system in a structured form.
|
||||
*/
|
||||
// StructuredRemittanceInformation6 structuredRemittanceInformation6 =
|
||||
// factory.createStructuredRemittanceInformation6();
|
||||
// remittanceInformation1.getStrd().add(structuredRemittanceInformation6);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fill the BIC information. If the BIC is not provided or in Iban only mode, we put
|
||||
* NOTPROVIDED value. In this case, the bank ignore the BIC and use the Iban only.
|
||||
*
|
||||
* @param finInstnId The financial instituation identification tag of the generated file.
|
||||
* @param bank The bank from which the BIC is get.
|
||||
*/
|
||||
protected void fillBic(FinancialInstitutionIdentification5Choice finInstnId, Bank bank) {
|
||||
|
||||
if (bankOrderFileFormat.getIbanOnly()
|
||||
|| bank == null
|
||||
|| Strings.isNullOrEmpty(bank.getCode())) {
|
||||
GenericIdentification3 genId = new GenericIdentification3();
|
||||
genId.setId(BIC_NOT_PROVIDED);
|
||||
finInstnId.setPrtryId(genId);
|
||||
} else {
|
||||
finInstnId.setBIC(bank.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,702 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder.file.directdebit;
|
||||
|
||||
import com.axelor.apps.account.db.Umr;
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.bankpayment.service.config.BankPaymentConfigService;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.AccountIdentification4Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.ActiveOrHistoricCurrencyAndAmount;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.BranchAndFinancialInstitutionIdentification4;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.CashAccount16;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.ChargeBearerType1Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.CustomerDirectDebitInitiationV02;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.DirectDebitTransaction6;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.DirectDebitTransactionInformation9;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.Document;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.FinancialInstitutionIdentification7;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.GenericFinancialIdentification1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.GenericPersonIdentification1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.GroupHeader39;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.LocalInstrument2Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.MandateRelatedInformation6;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.ObjectFactory;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.Party6Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.PartyIdentification32;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.PaymentIdentification1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.PaymentInstructionInformation4;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.PaymentMethod2Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.PaymentTypeInformation20;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.PersonIdentification5;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.PersonIdentificationSchemeName1Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.RemittanceInformation5;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.SequenceType1Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02.ServiceLevel8Choice;
|
||||
import com.axelor.apps.base.db.Bank;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import javax.xml.datatype.DatatypeFactory;
|
||||
|
||||
public class BankOrderFile00800102Service extends BankOrderFile008Service {
|
||||
|
||||
protected ObjectFactory factory;
|
||||
protected String sepaType;
|
||||
|
||||
@Inject
|
||||
public BankOrderFile00800102Service(BankOrder bankOrder, String sepaType) {
|
||||
super(bankOrder);
|
||||
|
||||
context = "com.axelor.apps.bankpayment.xsd.sepa.pain_008_001_02";
|
||||
|
||||
factory = new ObjectFactory();
|
||||
this.sepaType = sepaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the XML SEPA Direct Debit file (pain.008.001.02)
|
||||
*
|
||||
* @return the SEPA Direct Debit file (pain.008.001.02)
|
||||
* @throws JAXBException
|
||||
* @throws IOException
|
||||
* @throws AxelorException
|
||||
* @throws DatatypeConfigurationException
|
||||
*/
|
||||
@Override
|
||||
public File generateFile()
|
||||
throws JAXBException, IOException, AxelorException, DatatypeConfigurationException {
|
||||
// Creditor
|
||||
PartyIdentification32 creditor = factory.createPartyIdentification32();
|
||||
creditor.setNm(senderBankDetails.getOwnerName());
|
||||
|
||||
/*
|
||||
* Hierarchy of a XML file
|
||||
*
|
||||
* GroupHeader : This building block is mandatory and present once.
|
||||
* It contains elements such as Message Identification,
|
||||
* Creation Date And Time, Grouping indicator.
|
||||
* Payment Information : This building block is mandatory and repetitive.
|
||||
* It contains, among other things, elements related
|
||||
* to the Credit side of the transaction, such as
|
||||
* Creditor and Payment Type Information.
|
||||
* Direct Debit Transaction Information : This building block is mandatory and repetitive.
|
||||
* It contains, among other things, elements related
|
||||
* to the debit side of the transaction, such as
|
||||
* Debtor and Remittance Information Rules.
|
||||
*
|
||||
* <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
* <Document xmlns="urn:iso:std:iso:20022:tech:xsd:pain.008.001.02">
|
||||
* <CstmrDrctDbtInitn>
|
||||
* <GrpHdr> <-- occ : 1..1
|
||||
* </GrpHdr>
|
||||
* <PmtInf> <-- occ : 1..n
|
||||
* <DrctDbtTxInf> <-- occ : 1..n
|
||||
* </DrctDbtTxInf>
|
||||
* </PmtInf>
|
||||
* </CstmrDrctDbtInitn>
|
||||
* </Document>
|
||||
*/
|
||||
|
||||
/*
|
||||
* Document, <Document> tag
|
||||
*/
|
||||
Document document = factory.createDocument();
|
||||
|
||||
/*
|
||||
* Customer Direct Debit Initiation, <CstmrDrctDbtInitn> tag
|
||||
*/
|
||||
CustomerDirectDebitInitiationV02 customerDirectDebitInitiationV02 =
|
||||
factory.createCustomerDirectDebitInitiationV02();
|
||||
document.setCstmrDrctDbtInitn(customerDirectDebitInitiationV02);
|
||||
|
||||
/*
|
||||
* Group Header, <GrpHdr> tag
|
||||
* Set of characteristics shared by all individual transactions included in the message.
|
||||
*/
|
||||
GroupHeader39 groupHeader = factory.createGroupHeader39();
|
||||
createGrpHdr(groupHeader, creditor);
|
||||
customerDirectDebitInitiationV02.setGrpHdr(groupHeader);
|
||||
|
||||
/*
|
||||
* Payment Information, <PmtInf> tag
|
||||
* Does not need to set the List<PaymentInstructionInformation4> to the customerDirectDebitInitiationV02 object (see doc).
|
||||
*/
|
||||
createPmtInf(customerDirectDebitInitiationV02.getPmtInf(), creditor);
|
||||
|
||||
fileToCreate = factory.createDocument(document);
|
||||
return super.generateFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the GroupHeader part ({@code <GrpHdr>} tag) of the file, into the provided {@link
|
||||
* GroupHeader39} object
|
||||
*
|
||||
* @param groupHeader the {@link GroupHeader39} to build
|
||||
* @param creditor the creditor of the SEPA Direct Debit file
|
||||
* @throws DatatypeConfigurationException
|
||||
*/
|
||||
protected void createGrpHdr(GroupHeader39 groupHeader, PartyIdentification32 creditor)
|
||||
throws DatatypeConfigurationException {
|
||||
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
|
||||
|
||||
/*
|
||||
* Message Identification (mandatory)
|
||||
* Point to point reference assigned by the instructing party and sent to the next party in the chain to unambiguously identify the message.
|
||||
*/
|
||||
groupHeader.setMsgId(bankOrderSeq);
|
||||
|
||||
/*
|
||||
* Creation Date Time (mandatory)
|
||||
* Date and time at which a (group of) payment instruction(s) was created by the instructing party.
|
||||
*
|
||||
* Format : YYYY-MM-DDThh:mm:ss
|
||||
* Example : <CreDtTm>2010-12-02T08:35:30</CreDtTm>
|
||||
*/
|
||||
groupHeader.setCreDtTm(
|
||||
datatypeFactory.newXMLGregorianCalendar(
|
||||
generationDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))));
|
||||
|
||||
/*
|
||||
* Number Of Transactions (mandatory)
|
||||
* Number of individual transactions contained in the message.
|
||||
*/
|
||||
groupHeader.setNbOfTxs(Integer.toString(nbOfLines));
|
||||
|
||||
/*
|
||||
* Control Sum
|
||||
* Total of all individual amounts included in the message, irrespective of currencies
|
||||
*
|
||||
* Format : Max. 18 digits of which 2 for the fractional part.
|
||||
* Decimal separator is "."
|
||||
*/
|
||||
groupHeader.setCtrlSum(arithmeticTotal);
|
||||
|
||||
/*
|
||||
* Initiating Party (mandatory)
|
||||
* Party initiating the payment. In the direct debit context, this can be the creditor, or the party that initiates the payment on behalf of the creditor.
|
||||
*/
|
||||
groupHeader.setInitgPty(creditor);
|
||||
|
||||
/*
|
||||
* Pas documenté dans le fichier
|
||||
*/
|
||||
// groupHeader.setFwdgAgt(???);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the PaymentInformation part ({@code <PmtInf>} tag) of the file, and adds it into the
|
||||
* provided {@link PaymentInstructionInformation4} list
|
||||
*
|
||||
* @param paymentInstructionInformationList the list to add the {@link
|
||||
* PaymentInstructionInformation4} objects into
|
||||
* @param creditor the creditor of the SEPA Direct Debit file
|
||||
* @throws DatatypeConfigurationException
|
||||
*/
|
||||
protected void createPmtInf(
|
||||
List<PaymentInstructionInformation4> paymentInstructionInformationList,
|
||||
PartyIdentification32 creditor)
|
||||
throws AxelorException, DatatypeConfigurationException {
|
||||
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
|
||||
|
||||
/*
|
||||
* Payment Information (mandatory)
|
||||
* Set of characteristics that apply to the credit side of the payment transactions included in the direct debit transaction initiation.
|
||||
*/
|
||||
PaymentInstructionInformation4 paymentInstructionInformation4 =
|
||||
factory.createPaymentInstructionInformation4();
|
||||
paymentInstructionInformationList.add(paymentInstructionInformation4);
|
||||
|
||||
/*
|
||||
* Payment Information Identification (mandatory)
|
||||
* Reference assigned by a sending party to unambiguously identify the payment information block within the message.
|
||||
*/
|
||||
paymentInstructionInformation4.setPmtInfId(bankOrderSeq);
|
||||
|
||||
/*
|
||||
* Payment Method (mandatory, always 'DD')
|
||||
* Specifies the means of payment that will be used to move the amount of money.
|
||||
*/
|
||||
paymentInstructionInformation4.setPmtMtd(PaymentMethod2Code.DD);
|
||||
|
||||
/*
|
||||
* Batch Booking (optional)
|
||||
* Identifies whether a single entry per individual transaction or a batch entry for the sum of the amounts of all transactions in the group is required.
|
||||
*
|
||||
* Usage : Recommended "true". If absent then default "true".
|
||||
*
|
||||
* 'true' if : Identifies that a batch entry for the sum of the amounts of all
|
||||
* transactions in a Payment Information Block is required.
|
||||
* (one credit for all transactions in a Payment Information Block)
|
||||
* 'false' if : Identifies that a single entry for each of the transactions
|
||||
* in a message is required.
|
||||
*/
|
||||
paymentInstructionInformation4.setBtchBookg(true);
|
||||
|
||||
/*
|
||||
* Number Of Transactions (optional)
|
||||
* Number of individual transactions contained in the message.
|
||||
*/
|
||||
paymentInstructionInformation4.setNbOfTxs(Integer.toString(nbOfLines));
|
||||
|
||||
/*
|
||||
* Control Sum (optional)
|
||||
* Total of all individual amounts included in the payment block, irrespective of currencies.
|
||||
*
|
||||
* Format : Max. 18 digits of which 2 for the fractional part.
|
||||
* Decimal separator is "."
|
||||
*/
|
||||
paymentInstructionInformation4.setCtrlSum(arithmeticTotal);
|
||||
|
||||
/*
|
||||
* Payment Type Information (mandatory)
|
||||
* Set of elements that further specifies the type of transaction.
|
||||
*/
|
||||
PaymentTypeInformation20 paymentTypeInformation20 = factory.createPaymentTypeInformation20();
|
||||
paymentInstructionInformation4.setPmtTpInf(paymentTypeInformation20);
|
||||
|
||||
/*
|
||||
* ServiceLevel (mandatory)
|
||||
* Agreement under which or rules under which the transaction should be processed.
|
||||
*/
|
||||
ServiceLevel8Choice serviceLevel8Choice = factory.createServiceLevel8Choice();
|
||||
paymentTypeInformation20.setSvcLvl(serviceLevel8Choice);
|
||||
/*
|
||||
* Code (mandatory, always 'SEPA')
|
||||
* Identification of a pre-agreed level of service between the parties in a coded form.
|
||||
*/
|
||||
serviceLevel8Choice.setCd("SEPA");
|
||||
|
||||
/*
|
||||
* Local Instrument (mandatory)
|
||||
* User community specific instrument.
|
||||
*/
|
||||
LocalInstrument2Choice localInstrument2Choice = factory.createLocalInstrument2Choice();
|
||||
/*
|
||||
* Code (mandatory)
|
||||
*
|
||||
* Format : either 'CORE' or 'B2B'
|
||||
* Rule : The mixing of Core Direct Debits and Business-to-Business Direct Debits is not
|
||||
* allowed in the same message.
|
||||
*/
|
||||
switch (sepaType) {
|
||||
case SEPA_TYPE_CORE:
|
||||
localInstrument2Choice.setCd(SEPA_TYPE_CORE);
|
||||
break;
|
||||
case SEPA_TYPE_SBB:
|
||||
localInstrument2Choice.setCd(SEPA_TYPE_SBB);
|
||||
break;
|
||||
default:
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_FILE_UNKNOWN_SEPA_TYPE));
|
||||
}
|
||||
paymentTypeInformation20.setLclInstrm(localInstrument2Choice);
|
||||
|
||||
/*
|
||||
* Sequence Type (mandatory) // TO CHECK
|
||||
* Identifies the direct debit sequence, e.g. first, recurrent, final or one-off.
|
||||
*
|
||||
* Either one of the following values.
|
||||
* CODE Name Definition
|
||||
* ------------------------------------------------------------------------------------
|
||||
* FRST First First collection of a series of direct debit instructions.
|
||||
* RCUR Recurrent Direct debit instruction where the debtor's authorisation is used for
|
||||
* regular direct debit transactions initiated by the creditor.
|
||||
* FNAL Final Final collection of a series of direct debit instructions.
|
||||
* OOFF One Off Direct debit instruction where the debtor's authorisation is used to
|
||||
* initiate one single direct debit transaction.
|
||||
*/
|
||||
paymentTypeInformation20.setSeqTp(SequenceType1Code.FRST);
|
||||
|
||||
/*
|
||||
* Category Purpose (optional)
|
||||
* Specifies the purpose of the payment based on a set of pre-defined categories.
|
||||
*/
|
||||
// CategoryPurpose1Choice categoryPurpose1Choice = factory.createCategoryPurpose1Choice();
|
||||
// paymentTypeInformation20.setCtgyPurp(categoryPurpose1Choice);
|
||||
/*
|
||||
* Code (mandatory)
|
||||
* Specifies the underlying reason of the payment transaction.
|
||||
*
|
||||
* iso20022.org -> 'PaymentCategoryPurpose1Code' for all codes available and definitions.
|
||||
*/
|
||||
// categoryPurpose1Choice.setCd("CASH");
|
||||
|
||||
/*
|
||||
* Requested Collection Date (mandatory)
|
||||
* Date at which the creditor requests the amount of money to be collected from the debtor.
|
||||
*
|
||||
* Format : YYYY-MM-DD
|
||||
* Usage : The minimum delay between sending date and requested collection date is depending
|
||||
* on the type of direct debit (B2B or CORE) and on the sequence type (FRST, OOFF,
|
||||
* RCUR, FNAL).
|
||||
*/
|
||||
paymentInstructionInformation4.setReqdColltnDt(
|
||||
datatypeFactory.newXMLGregorianCalendar(
|
||||
bankOrderDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
|
||||
|
||||
/*
|
||||
* Creditor (mandatory)
|
||||
* Party to which an amount of money is due.
|
||||
*/
|
||||
paymentInstructionInformation4.setCdtr(creditor);
|
||||
|
||||
/*
|
||||
* Creditor Account (mandatory)
|
||||
* Unambiguous identification of the account of the creditor to which a credit entry will be posted as a result of the payment transaction.
|
||||
*/
|
||||
CashAccount16 cashAccount16 = factory.createCashAccount16();
|
||||
/*
|
||||
* IBAN (mandatory)
|
||||
*/
|
||||
AccountIdentification4Choice accountIdentification4Choice =
|
||||
factory.createAccountIdentification4Choice();
|
||||
accountIdentification4Choice.setIBAN(senderBankDetails.getIban());
|
||||
cashAccount16.setId(accountIdentification4Choice);
|
||||
/*
|
||||
* Currency (optional)
|
||||
*
|
||||
* Rule : Currency of the account must be EUR. For usage of another currency, please
|
||||
* contact your bank.
|
||||
*/
|
||||
cashAccount16.setCcy(CURRENCY_CODE);
|
||||
|
||||
paymentInstructionInformation4.setCdtrAcct(cashAccount16);
|
||||
|
||||
/*
|
||||
* Creditor Agent (mandatory)
|
||||
* Financial institution servicing an account for the creditor.
|
||||
*
|
||||
* Note : The Bank Identifier Code (BIC) is composed of 8 or 11 characters, of which only the
|
||||
* first 8 characters are significant.
|
||||
*/
|
||||
FinancialInstitutionIdentification7 financialInstitutionIdentification7 =
|
||||
factory.createFinancialInstitutionIdentification7();
|
||||
|
||||
fillBic(financialInstitutionIdentification7, senderBankDetails.getBank()); // BIC
|
||||
|
||||
BranchAndFinancialInstitutionIdentification4 branchAndFinancialInstitutionIdentification4 =
|
||||
factory.createBranchAndFinancialInstitutionIdentification4();
|
||||
branchAndFinancialInstitutionIdentification4.setFinInstnId(financialInstitutionIdentification7);
|
||||
paymentInstructionInformation4.setCdtrAgt(branchAndFinancialInstitutionIdentification4);
|
||||
|
||||
/*
|
||||
* Ultimate Creditor (optional)
|
||||
* Ultimate party to which an amount of money is due. Ultimate Creditor is only to be used if different from Creditor.
|
||||
*/
|
||||
// paymentInstructionInformation4.setUltmtCdtr();
|
||||
|
||||
/*
|
||||
* Charge Bearer (mandatory) // TO CHECK
|
||||
* Specifies which party/parties will bear the charges associated with the processing of the payment transaction.
|
||||
*
|
||||
* CODE Name Description
|
||||
* ----------------------------------------------------------------------------------------
|
||||
* DEBT BorneByDebtor All transaction charges are to be borne by the debtor
|
||||
* CRED BorneByCreditor All transaction charges are to be borne by the creditor
|
||||
* SHAR Shared In a direct debit context, means that transaction charges on
|
||||
* the sender side are to be borne by the creditor, transaction
|
||||
* charges on the receiver side are to be borne by the debtor.
|
||||
* SLEV FollowingServiceLevel Charges are to be applied following the rules agreed in the
|
||||
* service level and/or scheme.
|
||||
*/
|
||||
paymentInstructionInformation4.setChrgBr(ChargeBearerType1Code.SLEV);
|
||||
|
||||
/*
|
||||
* Creditor Scheme Identification (optional)
|
||||
* Credit party that signs the Direct Debit mandate.
|
||||
*/
|
||||
// paymentInstructionInformation4.setCdtrSchmeId(creditor);
|
||||
|
||||
/*
|
||||
* Direct Debit Transaction Information, <DrctDbtTxInf> tag
|
||||
* Does not need to set the List<DirectDebitTransactionInformation1> to the paymentInstructionInformation2 object (see doc)
|
||||
*/
|
||||
createDrctDbtTxInf(paymentInstructionInformation4.getDrctDbtTxInf(), creditor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the DirectDebitTransactionInformation part ({@code <DrctDbtTxInf>} tag) of the file, and
|
||||
* adds it into the provided {@link DirectDebitTransactionInformation9} list
|
||||
*
|
||||
* @param directDebitTransactionInformation9List the list to add the {@link
|
||||
* DirectDebitTransactionInformation9} objects into
|
||||
* @param creditor the creditor of the SEPA Direct Debit file
|
||||
* @throws DatatypeConfigurationException
|
||||
* @throws AxelorException
|
||||
*/
|
||||
protected void createDrctDbtTxInf(
|
||||
List<DirectDebitTransactionInformation9> directDebitTransactionInformation9List,
|
||||
PartyIdentification32 creditor)
|
||||
throws DatatypeConfigurationException, AxelorException {
|
||||
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
|
||||
|
||||
for (BankOrderLine bankOrderLine : bankOrderLineList) {
|
||||
|
||||
BankDetails receiverBankDetails = bankOrderLine.getReceiverBankDetails();
|
||||
Umr receiverUmr = bankOrderLine.getPartner().getActiveUmr();
|
||||
|
||||
if (receiverUmr == null) {
|
||||
throw new AxelorException(
|
||||
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
|
||||
I18n.get(IExceptionMessage.DIRECT_DEBIT_MISSING_PARTNER_ACTIVE_UMR));
|
||||
}
|
||||
|
||||
/*
|
||||
* Direct Debit Transaction Information (mandatory)
|
||||
* Set of elements providing information specific to the individual transaction(s) included in the message.
|
||||
*/
|
||||
DirectDebitTransactionInformation9 directDebitTransactionInformation9 =
|
||||
factory.createDirectDebitTransactionInformation9();
|
||||
directDebitTransactionInformation9List.add(directDebitTransactionInformation9);
|
||||
|
||||
/*
|
||||
* Payment Identification (mandatory)
|
||||
* Set of elements to reference a payment instruction.
|
||||
*/
|
||||
PaymentIdentification1 paymentIdentification1 = factory.createPaymentIdentification1();
|
||||
directDebitTransactionInformation9.setPmtId(paymentIdentification1);
|
||||
/*
|
||||
* Instruction Identification (optional)
|
||||
* The Instruction Identification is a unique reference assigned by the Initiator to unambiguously identify the transaction.
|
||||
* It can be used in status messages related to the transaction.
|
||||
*/
|
||||
// paymentIdentification1.setInstrId();
|
||||
/*
|
||||
* End To End Identification (mandatory)
|
||||
* Unique identification assigned by the initiating party to unumbiguously identify the transaction.
|
||||
* This identification is passed on, unchanged, throughout the entire end-to-end chain.
|
||||
*/
|
||||
paymentIdentification1.setEndToEndId(bankOrderLine.getSequence());
|
||||
|
||||
/*
|
||||
* Instructed Amount (mandatory)
|
||||
* Amount of the direct debit, expressed in euro.
|
||||
*
|
||||
* Format : Max. 11 digits of which 2 for the fractional part.
|
||||
* Decimal separator is "."
|
||||
* Currency "EUR" is explicit, and included in the XML tag.
|
||||
* Usage : Amount must be between 0.01 and 999999999.99
|
||||
*/
|
||||
ActiveOrHistoricCurrencyAndAmount activeOrHistoricCurrencyAndAmount =
|
||||
factory.createActiveOrHistoricCurrencyAndAmount();
|
||||
activeOrHistoricCurrencyAndAmount.setCcy(CURRENCY_CODE);
|
||||
activeOrHistoricCurrencyAndAmount.setValue(bankOrderLine.getBankOrderAmount());
|
||||
directDebitTransactionInformation9.setInstdAmt(activeOrHistoricCurrencyAndAmount);
|
||||
|
||||
/*
|
||||
* Direct Debit Transaction (mandatory)
|
||||
* Set of elements providing information specific to the direct debit mandate.
|
||||
*/
|
||||
DirectDebitTransaction6 directDebitTransaction6 = factory.createDirectDebitTransaction6();
|
||||
directDebitTransactionInformation9.setDrctDbtTx(directDebitTransaction6);
|
||||
/*
|
||||
* Mandate Related Information (mandatory)
|
||||
* Set of elements used to provide further details related to a direct debit mandate signed between the creditor and the debtor.
|
||||
*/
|
||||
MandateRelatedInformation6 mandateRelatedInformation6 =
|
||||
factory.createMandateRelatedInformation6();
|
||||
directDebitTransaction6.setMndtRltdInf(mandateRelatedInformation6);
|
||||
/*
|
||||
* Mandate Identification (mandatory)
|
||||
* Reference of the direct debit mandate that has been signed between by the debtor and the creditor.
|
||||
*/
|
||||
mandateRelatedInformation6.setMndtId(receiverUmr.getUmrNumber());
|
||||
/*
|
||||
* Date of Signature (mandatory)
|
||||
* Date on which the direct debit mandate has been signed by the debtor.
|
||||
*
|
||||
* Format : YYYY-MM-DD
|
||||
*/
|
||||
mandateRelatedInformation6.setDtOfSgntr(
|
||||
datatypeFactory.newXMLGregorianCalendar(
|
||||
receiverUmr
|
||||
.getMandateSignatureDate()
|
||||
.format(DateTimeFormatter.ofPattern(("yyyy-MM-dd")))));
|
||||
/*
|
||||
* Amendment Indicator (optional)
|
||||
* Indicator notifying whether the underlying mandate is amended or not.
|
||||
*
|
||||
* Usage : - If not present, considered as "false".
|
||||
* - If true, 'Amendment Information Details' is mandatory.
|
||||
*
|
||||
* 'true' if : The mandate is amended or migrated from Dom'80.
|
||||
* 'false' if : The mandate is not amended.
|
||||
*/
|
||||
// mandateRelatedInformation6.setAmdmntInd(???);
|
||||
/*
|
||||
* Amendment Info Details (optional)
|
||||
* List of direct debit mandate elements that have been modified.
|
||||
*/
|
||||
// AmendmentInformationDetails6 amendmentInformationDetails6 =
|
||||
// factory.createAmendmentInformationDetails6();
|
||||
// mandateRelatedInformation6.setAmdmntInfDtls(amendmentInformationDetails6);
|
||||
// amendmentInformationDetails6.setOrgnlMndtId(???);
|
||||
// amendmentInformationDetails6.setOrgnlCdtrSchmeId(???);
|
||||
// amendmentInformationDetails6.setOrgnlDbtrAcct(???);
|
||||
// amendmentInformationDetails6.setOrgnlDbtrAgt(???);
|
||||
/*
|
||||
* Electronic Signature (optional)
|
||||
* Digital signature as provided by the creditor.
|
||||
*
|
||||
* Usage : - If the direct debit is based on an electronic mandate, this data
|
||||
* element must contain the reference of the Mandate Acceptance Report.
|
||||
* - If the direct debit is based on a paper mandate, this data element
|
||||
* is not allowed.
|
||||
*/
|
||||
// mandateRelatedInformation6.setElctrncSgntr(???);
|
||||
/*
|
||||
* Creditor Scheme Identification
|
||||
* Creditor identification as given by his bank.
|
||||
*/
|
||||
PartyIdentification32 creditorSchemeId = factory.createPartyIdentification32();
|
||||
directDebitTransaction6.setCdtrSchmeId(creditorSchemeId);
|
||||
Party6Choice party6Choice = factory.createParty6Choice();
|
||||
creditorSchemeId.setId(party6Choice);
|
||||
PersonIdentification5 personIdentification5 = factory.createPersonIdentification5();
|
||||
party6Choice.setPrvtId(personIdentification5);
|
||||
GenericPersonIdentification1 genericPersonIdentification1 =
|
||||
factory.createGenericPersonIdentification1();
|
||||
personIdentification5.getOthr().add(genericPersonIdentification1);
|
||||
genericPersonIdentification1.setId(
|
||||
Beans.get(BankPaymentConfigService.class)
|
||||
.getIcsNumber(senderCompany.getBankPaymentConfig()));
|
||||
PersonIdentificationSchemeName1Choice personIdentificationSchemeName1Choice =
|
||||
factory.createPersonIdentificationSchemeName1Choice();
|
||||
genericPersonIdentification1.setSchmeNm(personIdentificationSchemeName1Choice);
|
||||
personIdentificationSchemeName1Choice.setPrtry("SEPA");
|
||||
|
||||
/*
|
||||
* Ultimate Creditor (optional)
|
||||
* Ultimate party to which an amount of money is due. Ultimate Creditor is only to be used if different from Creditor.
|
||||
*/
|
||||
// directDebitTransaction6.setUltmtCdtr();
|
||||
|
||||
/*
|
||||
* Debtor Agent (mandatory)
|
||||
* Financial institution servicing an account for the debtor.
|
||||
*/
|
||||
BranchAndFinancialInstitutionIdentification4 branchAndFinancialInstitutionIdentification4 =
|
||||
factory.createBranchAndFinancialInstitutionIdentification4();
|
||||
FinancialInstitutionIdentification7 financialInstitutionIdentification7 =
|
||||
factory.createFinancialInstitutionIdentification7();
|
||||
|
||||
fillBic(financialInstitutionIdentification7, receiverBankDetails.getBank()); // BIC
|
||||
|
||||
branchAndFinancialInstitutionIdentification4.setFinInstnId(
|
||||
financialInstitutionIdentification7);
|
||||
directDebitTransactionInformation9.setDbtrAgt(branchAndFinancialInstitutionIdentification4);
|
||||
|
||||
/*
|
||||
* Debtor (mandatory)
|
||||
* Party that owes an amount of money to the (ultimate) creditor.
|
||||
*/
|
||||
PartyIdentification32 debtor = factory.createPartyIdentification32();
|
||||
debtor.setNm(receiverBankDetails.getOwnerName());
|
||||
directDebitTransactionInformation9.setDbtr(debtor);
|
||||
|
||||
/*
|
||||
* Debtor Account (mandatory)
|
||||
* Identification of the account of the debtor to which a debit entry will be made to execute the transfer.
|
||||
*/
|
||||
AccountIdentification4Choice accountIdentification4Choice =
|
||||
factory.createAccountIdentification4Choice();
|
||||
accountIdentification4Choice.setIBAN(receiverBankDetails.getIban());
|
||||
CashAccount16 cashAccount16 = factory.createCashAccount16();
|
||||
cashAccount16.setId(accountIdentification4Choice);
|
||||
directDebitTransactionInformation9.setDbtrAcct(cashAccount16);
|
||||
|
||||
/*
|
||||
* Ultimate Debtor (optional)
|
||||
* Ultimate party that owes an amount of money to the (ultimate) creditor. Ultimate Debtor is only to be used if different from Debtor.
|
||||
*/
|
||||
// directDebitTransactionInformation9.setUltmtDbtr(???);
|
||||
|
||||
/*
|
||||
* Purpose (optional)
|
||||
* Underlying reason for the payment transaction.
|
||||
* Purpose is used by the Debtor to provide information to the Creditor, concerning thenature of the payment transaction.
|
||||
* It is not used for processing by any of the banks involved.
|
||||
*/
|
||||
// Purpose2Choice purpose2Choice = factory.createPurpose2Choice();
|
||||
// directDebitTransactionInformation9.setPurp(purpose2Choice);
|
||||
/*
|
||||
* Code (mandatory)
|
||||
* Specifies the underlying reason of the payment transaction.
|
||||
*/
|
||||
// purpose2Choice.setCd(???);
|
||||
|
||||
/*
|
||||
* Remittance Information (optional)
|
||||
* Information that enables the matching, ie, reconciliation, of a payment with the items that the payment
|
||||
* is intended to settle, eg, commercial invoices in an account receivable system.
|
||||
*
|
||||
* Usage : Either Structured or Unstructured, but not both.
|
||||
*/
|
||||
RemittanceInformation5 remittanceInformation5 = factory.createRemittanceInformation5();
|
||||
directDebitTransactionInformation9.setRmtInf(remittanceInformation5);
|
||||
/*
|
||||
* Unstructured (choice 1 of 2)
|
||||
* Information supplied to enable the matching of an entry with the items that the transfer is intended
|
||||
* to settle, eg, commercial invoices in an accounts' receivable system in an unstructured form.
|
||||
*/
|
||||
remittanceInformation5.getUstrd().add(bankOrderLine.getReceiverReference());
|
||||
|
||||
/*
|
||||
* Structured (choice 2 of 2)
|
||||
* Information supplied to enable the matching of an entry with the items that the transfer is intended
|
||||
* to settle, eg, commercial invoices in an accounts' receivable system in a structured form.
|
||||
*/
|
||||
// StructuredRemittanceInformation7 structuredRemittanceInformation7 =
|
||||
// factory.createStructuredRemittanceInformation7();
|
||||
// remittanceInformation5.getStrd().add(structuredRemittanceInformation7);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fill the BIC information. If the BIC is not provided or in Iban only mode, we put
|
||||
* NOTPROVIDED value. In this case, the bank ignore the BIC and use the Iban only.
|
||||
*
|
||||
* @param finInstnId The financial instituation identification tag of the generated file.
|
||||
* @param bank The bank from which the BIC is get.
|
||||
*/
|
||||
protected void fillBic(FinancialInstitutionIdentification7 finInstnId, Bank bank) {
|
||||
|
||||
if (bankOrderFileFormat.getIbanOnly()
|
||||
|| bank == null
|
||||
|| Strings.isNullOrEmpty(bank.getCode())) {
|
||||
GenericFinancialIdentification1 genFinId = new GenericFinancialIdentification1();
|
||||
genFinId.setId(BIC_NOT_PROVIDED);
|
||||
finInstnId.setOthr(genFinId);
|
||||
} else {
|
||||
finInstnId.setBIC(bank.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder.file.directdebit;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.BankOrderFileService;
|
||||
|
||||
public abstract class BankOrderFile008Service extends BankOrderFileService {
|
||||
|
||||
public static final String SEPA_TYPE_CORE = "CORE";
|
||||
public static final String SEPA_TYPE_SBB = "SBB";
|
||||
protected static final String BIC_NOT_PROVIDED = "NOTPROVIDED";
|
||||
protected static final String CURRENCY_CODE = "EUR";
|
||||
|
||||
public BankOrderFile008Service(BankOrder bankOrder) {
|
||||
super(bankOrder);
|
||||
|
||||
fileExtension = FILE_EXTENSION_XML;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,265 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder.file.transfer;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.BankOrderFileService;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.AccountIdentification3Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.AmountType2Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.BranchAndFinancialInstitutionIdentification3;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.CashAccount7;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.CreditTransferTransactionInformation1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.CurrencyAndAmount;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.Document;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.FinancialInstitutionIdentification5Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.GenericIdentification3;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.GroupHeader1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.Grouping1Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.ObjectFactory;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.Pain00100102;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.PartyIdentification8;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.PaymentIdentification1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.PaymentInstructionInformation1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.PaymentMethod3Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.PaymentTypeInformation1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.RemittanceInformation1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.ServiceLevel1Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02.ServiceLevel2Choice;
|
||||
import com.axelor.apps.base.db.Bank;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import javax.xml.datatype.DatatypeFactory;
|
||||
|
||||
public class BankOrderFile00100102Service extends BankOrderFileService {
|
||||
|
||||
protected static final String BIC_NOT_PROVIDED = "NOTPROVIDED";
|
||||
|
||||
@Inject
|
||||
public BankOrderFile00100102Service(BankOrder bankOrder) {
|
||||
|
||||
super(bankOrder);
|
||||
|
||||
context = "com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_02";
|
||||
fileExtension = FILE_EXTENSION_XML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create an XML file for SEPA transfer pain.001.001.02
|
||||
*
|
||||
* @throws AxelorException
|
||||
* @throws DatatypeConfigurationException
|
||||
* @throws JAXBException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public File generateFile()
|
||||
throws JAXBException, IOException, AxelorException, DatatypeConfigurationException {
|
||||
|
||||
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
|
||||
|
||||
ObjectFactory factory = new ObjectFactory();
|
||||
|
||||
ServiceLevel2Choice svcLvl = factory.createServiceLevel2Choice();
|
||||
svcLvl.setCd(ServiceLevel1Code.SEPA);
|
||||
|
||||
PaymentTypeInformation1 pmtTpInf = factory.createPaymentTypeInformation1();
|
||||
pmtTpInf.setSvcLvl(svcLvl);
|
||||
|
||||
// Payer
|
||||
PartyIdentification8 dbtr = factory.createPartyIdentification8();
|
||||
dbtr.setNm(senderBankDetails.getOwnerName());
|
||||
|
||||
// IBAN
|
||||
AccountIdentification3Choice iban = factory.createAccountIdentification3Choice();
|
||||
iban.setIBAN(senderBankDetails.getIban());
|
||||
|
||||
CashAccount7 dbtrAcct = factory.createCashAccount7();
|
||||
dbtrAcct.setId(iban);
|
||||
|
||||
// BIC
|
||||
FinancialInstitutionIdentification5Choice finInstnId =
|
||||
factory.createFinancialInstitutionIdentification5Choice();
|
||||
|
||||
fillBic(finInstnId, senderBankDetails.getBank());
|
||||
|
||||
BranchAndFinancialInstitutionIdentification3 dbtrAgt =
|
||||
factory.createBranchAndFinancialInstitutionIdentification3();
|
||||
dbtrAgt.setFinInstnId(finInstnId);
|
||||
|
||||
PaymentInstructionInformation1 pmtInf = factory.createPaymentInstructionInformation1();
|
||||
pmtInf.setPmtInfId(bankOrderSeq);
|
||||
pmtInf.setPmtMtd(PaymentMethod3Code.TRF);
|
||||
pmtInf.setPmtTpInf(pmtTpInf);
|
||||
|
||||
/**
|
||||
* RequestedExecutionDate Definition : Date at which the initiating party asks the Debtor's Bank
|
||||
* to process the payment. This is the date on which the debtor's account(s) is (are) to be
|
||||
* debited. XML Tag : <ReqdExctnDt> Occurrences : [1..1] Format : YYYY-MM-DD Rules : date is
|
||||
* limited to maximum one year in the future.
|
||||
*/
|
||||
pmtInf.setReqdExctnDt(
|
||||
datatypeFactory.newXMLGregorianCalendar(
|
||||
bankOrderDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
|
||||
pmtInf.setDbtr(dbtr);
|
||||
pmtInf.setDbtrAcct(dbtrAcct);
|
||||
pmtInf.setDbtrAgt(dbtrAgt);
|
||||
|
||||
CreditTransferTransactionInformation1 cdtTrfTxInf = null;
|
||||
PaymentIdentification1 pmtId = null;
|
||||
AmountType2Choice amt = null;
|
||||
CurrencyAndAmount instdAmt = null;
|
||||
PartyIdentification8 cbtr = null;
|
||||
CashAccount7 cbtrAcct = null;
|
||||
BranchAndFinancialInstitutionIdentification3 cbtrAgt = null;
|
||||
RemittanceInformation1 rmtInf = null;
|
||||
|
||||
for (BankOrderLine bankOrderLine : bankOrderLineList) {
|
||||
|
||||
BankDetails receiverBankDetails = bankOrderLine.getReceiverBankDetails();
|
||||
|
||||
// Reference
|
||||
pmtId = factory.createPaymentIdentification1();
|
||||
// pmtId.setInstrId(bankOrderLine.getSequence());
|
||||
pmtId.setEndToEndId(bankOrderLine.getSequence());
|
||||
|
||||
// Amount
|
||||
instdAmt = factory.createCurrencyAndAmount();
|
||||
instdAmt.setCcy(bankOrderCurrency.getCode());
|
||||
instdAmt.setValue(bankOrderLine.getBankOrderAmount());
|
||||
|
||||
amt = factory.createAmountType2Choice();
|
||||
amt.setInstdAmt(instdAmt);
|
||||
|
||||
// Receiver
|
||||
cbtr = factory.createPartyIdentification8();
|
||||
cbtr.setNm(receiverBankDetails.getOwnerName());
|
||||
|
||||
// IBAN
|
||||
iban = factory.createAccountIdentification3Choice();
|
||||
iban.setIBAN(receiverBankDetails.getIban());
|
||||
|
||||
cbtrAcct = factory.createCashAccount7();
|
||||
cbtrAcct.setId(iban);
|
||||
|
||||
// BIC
|
||||
finInstnId = factory.createFinancialInstitutionIdentification5Choice();
|
||||
|
||||
fillBic(finInstnId, receiverBankDetails.getBank());
|
||||
|
||||
cbtrAgt = factory.createBranchAndFinancialInstitutionIdentification3();
|
||||
cbtrAgt.setFinInstnId(finInstnId);
|
||||
|
||||
rmtInf = factory.createRemittanceInformation1();
|
||||
|
||||
String ustrd = "";
|
||||
if (!Strings.isNullOrEmpty(bankOrderLine.getReceiverReference())) {
|
||||
ustrd += bankOrderLine.getReceiverReference();
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(bankOrderLine.getReceiverLabel())) {
|
||||
if (!Strings.isNullOrEmpty(ustrd)) {
|
||||
ustrd += " - ";
|
||||
}
|
||||
ustrd += bankOrderLine.getReceiverLabel();
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(ustrd)) {
|
||||
rmtInf.getUstrd().add(ustrd);
|
||||
}
|
||||
|
||||
// StructuredRemittanceInformation6 strd = factory.createStructuredRemittanceInformation6();
|
||||
//
|
||||
// CreditorReferenceInformation1 cdtrRefInf = factory.createCreditorReferenceInformation1();
|
||||
// cdtrRefInf.setCdtrRef(bankOrderLine.getReceiverReference());
|
||||
//
|
||||
// strd.setCdtrRefInf(cdtrRefInf);
|
||||
//
|
||||
// rmtInf.getStrd().add(strd);
|
||||
|
||||
// Transaction
|
||||
cdtTrfTxInf = factory.createCreditTransferTransactionInformation1();
|
||||
cdtTrfTxInf.setPmtId(pmtId);
|
||||
cdtTrfTxInf.setAmt(amt);
|
||||
cdtTrfTxInf.setCdtr(cbtr);
|
||||
cdtTrfTxInf.setCdtrAcct(cbtrAcct);
|
||||
cdtTrfTxInf.setCdtrAgt(cbtrAgt);
|
||||
cdtTrfTxInf.setRmtInf(rmtInf);
|
||||
|
||||
pmtInf.getCdtTrfTxInf().add(cdtTrfTxInf);
|
||||
}
|
||||
|
||||
// Header
|
||||
GroupHeader1 grpHdr = factory.createGroupHeader1();
|
||||
|
||||
/** Référence du message qui n'est pas utilisée comme référence fonctionnelle. */
|
||||
grpHdr.setMsgId(bankOrderSeq);
|
||||
|
||||
/**
|
||||
* CreationDateTime Definition : Date and Time at which a (group of) payment instruction(s) was
|
||||
* created by the instructing party. XML Tag : <CreDtTm> Occurrences : [1..1] Format :
|
||||
* YYYY-MM-DDThh:mm:ss
|
||||
*/
|
||||
grpHdr.setCreDtTm(
|
||||
datatypeFactory.newXMLGregorianCalendar(
|
||||
generationDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))));
|
||||
grpHdr.setNbOfTxs(Integer.toString(nbOfLines));
|
||||
grpHdr.setCtrlSum(arithmeticTotal);
|
||||
grpHdr.setGrpg(Grouping1Code.MIXD);
|
||||
grpHdr.setInitgPty(dbtr);
|
||||
|
||||
// Parent
|
||||
Pain00100102 pain00100102 = factory.createPain00100102();
|
||||
pain00100102.setGrpHdr(grpHdr);
|
||||
pain00100102.getPmtInf().add(pmtInf);
|
||||
|
||||
// Document
|
||||
Document xml = factory.createDocument();
|
||||
xml.setPain00100102(pain00100102);
|
||||
|
||||
fileToCreate = factory.createDocument(xml);
|
||||
|
||||
return super.generateFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fill the BIC information. If the BIC is not provided or in Iban only mode, we put
|
||||
* NOTPROVIDED value. In this case, the bank ignore the BIC and use the Iban only.
|
||||
*
|
||||
* @param finInstnId The financial instituation identification tag of the generated file.
|
||||
* @param bank The bank from which the BIC is get.
|
||||
*/
|
||||
protected void fillBic(FinancialInstitutionIdentification5Choice finInstnId, Bank bank) {
|
||||
|
||||
if (bankOrderFileFormat.getIbanOnly()
|
||||
|| bank == null
|
||||
|| Strings.isNullOrEmpty(bank.getCode())) {
|
||||
GenericIdentification3 genId = new GenericIdentification3();
|
||||
genId.setId(BIC_NOT_PROVIDED);
|
||||
finInstnId.setPrtryId(genId);
|
||||
} else {
|
||||
finInstnId.setBIC(bank.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder.file.transfer;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.BankOrderFileService;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.AccountIdentification4Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.ActiveOrHistoricCurrencyAndAmount;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.AmountType3Choice;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.BranchAndFinancialInstitutionIdentification4;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.CashAccount16;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.CreditTransferTransactionInformation10;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.CustomerCreditTransferInitiationV03;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.Document;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.FinancialInstitutionIdentification7;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.GenericFinancialIdentification1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.GroupHeader32;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.ObjectFactory;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.PartyIdentification32;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.PaymentIdentification1;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.PaymentInstructionInformation3;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.PaymentMethod3Code;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.PaymentTypeInformation19;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.RemittanceInformation5;
|
||||
import com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03.ServiceLevel8Choice;
|
||||
import com.axelor.apps.base.db.Bank;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
import javax.xml.datatype.DatatypeFactory;
|
||||
|
||||
public class BankOrderFile00100103Service extends BankOrderFileService {
|
||||
|
||||
protected static final String BIC_NOT_PROVIDED = "NOTPROVIDED";
|
||||
|
||||
@Inject
|
||||
public BankOrderFile00100103Service(BankOrder bankOrder) {
|
||||
|
||||
super(bankOrder);
|
||||
|
||||
context = "com.axelor.apps.bankpayment.xsd.sepa.pain_001_001_03";
|
||||
fileExtension = FILE_EXTENSION_XML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create an XML file for SEPA transfer pain.001.001.03
|
||||
*
|
||||
* @throws AxelorException
|
||||
* @throws DatatypeConfigurationException
|
||||
* @throws JAXBException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public File generateFile()
|
||||
throws JAXBException, IOException, AxelorException, DatatypeConfigurationException {
|
||||
|
||||
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
|
||||
|
||||
ObjectFactory factory = new ObjectFactory();
|
||||
|
||||
ServiceLevel8Choice svcLvl = factory.createServiceLevel8Choice();
|
||||
svcLvl.setCd("SEPA");
|
||||
|
||||
PaymentTypeInformation19 pmtTpInf = factory.createPaymentTypeInformation19();
|
||||
pmtTpInf.setSvcLvl(svcLvl);
|
||||
|
||||
// Payer
|
||||
PartyIdentification32 dbtr = factory.createPartyIdentification32();
|
||||
dbtr.setNm(senderBankDetails.getOwnerName());
|
||||
|
||||
// IBAN
|
||||
AccountIdentification4Choice iban = factory.createAccountIdentification4Choice();
|
||||
iban.setIBAN(senderBankDetails.getIban());
|
||||
|
||||
CashAccount16 dbtrAcct = factory.createCashAccount16();
|
||||
dbtrAcct.setId(iban);
|
||||
|
||||
// BIC
|
||||
FinancialInstitutionIdentification7 finInstnId =
|
||||
factory.createFinancialInstitutionIdentification7();
|
||||
|
||||
fillBic(finInstnId, senderBankDetails.getBank());
|
||||
|
||||
BranchAndFinancialInstitutionIdentification4 dbtrAgt =
|
||||
factory.createBranchAndFinancialInstitutionIdentification4();
|
||||
dbtrAgt.setFinInstnId(finInstnId);
|
||||
|
||||
PaymentInstructionInformation3 pmtInf = factory.createPaymentInstructionInformation3();
|
||||
pmtInf.setPmtInfId(bankOrderSeq);
|
||||
pmtInf.setPmtMtd(PaymentMethod3Code.TRF);
|
||||
pmtInf.setPmtTpInf(pmtTpInf);
|
||||
|
||||
/**
|
||||
* RequestedExecutionDate Definition : Date at which the initiating party asks the Debtor's Bank
|
||||
* to process the payment. This is the date on which the debtor's account(s) is (are) to be
|
||||
* debited. XML Tag : <ReqdExctnDt> Occurrences : [1..1] Format : YYYY-MM-DD Rules : date is
|
||||
* limited to maximum one year in the future.
|
||||
*/
|
||||
pmtInf.setReqdExctnDt(
|
||||
datatypeFactory.newXMLGregorianCalendar(
|
||||
bankOrderDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
|
||||
pmtInf.setDbtr(dbtr);
|
||||
pmtInf.setDbtrAcct(dbtrAcct);
|
||||
pmtInf.setDbtrAgt(dbtrAgt);
|
||||
|
||||
CreditTransferTransactionInformation10 cdtTrfTxInf = null;
|
||||
PaymentIdentification1 pmtId = null;
|
||||
AmountType3Choice amt = null;
|
||||
ActiveOrHistoricCurrencyAndAmount instdAmt = null;
|
||||
PartyIdentification32 cbtr = null;
|
||||
CashAccount16 cbtrAcct = null;
|
||||
BranchAndFinancialInstitutionIdentification4 cbtrAgt = null;
|
||||
RemittanceInformation5 rmtInf = null;
|
||||
|
||||
for (BankOrderLine bankOrderLine : bankOrderLineList) {
|
||||
|
||||
BankDetails receiverBankDetails = bankOrderLine.getReceiverBankDetails();
|
||||
|
||||
// Reference
|
||||
pmtId = factory.createPaymentIdentification1();
|
||||
// pmtId.setInstrId(bankOrderLine.getSequence());
|
||||
pmtId.setEndToEndId(bankOrderLine.getSequence());
|
||||
|
||||
// Amount
|
||||
instdAmt = factory.createActiveOrHistoricCurrencyAndAmount();
|
||||
instdAmt.setCcy(bankOrderCurrency.getCode());
|
||||
instdAmt.setValue(bankOrderLine.getBankOrderAmount());
|
||||
|
||||
amt = factory.createAmountType3Choice();
|
||||
amt.setInstdAmt(instdAmt);
|
||||
|
||||
// Receiver
|
||||
cbtr = factory.createPartyIdentification32();
|
||||
cbtr.setNm(receiverBankDetails.getOwnerName());
|
||||
|
||||
// IBAN
|
||||
iban = factory.createAccountIdentification4Choice();
|
||||
iban.setIBAN(receiverBankDetails.getIban());
|
||||
|
||||
cbtrAcct = factory.createCashAccount16();
|
||||
cbtrAcct.setId(iban);
|
||||
|
||||
// BIC
|
||||
finInstnId = factory.createFinancialInstitutionIdentification7();
|
||||
|
||||
fillBic(finInstnId, receiverBankDetails.getBank());
|
||||
|
||||
cbtrAgt = factory.createBranchAndFinancialInstitutionIdentification4();
|
||||
cbtrAgt.setFinInstnId(finInstnId);
|
||||
|
||||
rmtInf = factory.createRemittanceInformation5();
|
||||
|
||||
String ustrd = "";
|
||||
if (!Strings.isNullOrEmpty(bankOrderLine.getReceiverReference())) {
|
||||
ustrd += bankOrderLine.getReceiverReference();
|
||||
}
|
||||
if (!Strings.isNullOrEmpty(bankOrderLine.getReceiverLabel())) {
|
||||
if (!Strings.isNullOrEmpty(ustrd)) {
|
||||
ustrd += " - ";
|
||||
}
|
||||
ustrd += bankOrderLine.getReceiverLabel();
|
||||
}
|
||||
|
||||
if (!Strings.isNullOrEmpty(ustrd)) {
|
||||
rmtInf.getUstrd().add(ustrd);
|
||||
}
|
||||
|
||||
// StructuredRemittanceInformation7 strd = factory.createStructuredRemittanceInformation7();
|
||||
//
|
||||
// CreditorReferenceInformation2 cdtrRefInf = factory.createCreditorReferenceInformation2();
|
||||
// cdtrRefInf.setRef(bankOrderLine.getReceiverReference());
|
||||
//
|
||||
// strd.setCdtrRefInf(cdtrRefInf);
|
||||
//
|
||||
// rmtInf.getStrd().add(strd);
|
||||
|
||||
// Transaction
|
||||
cdtTrfTxInf = factory.createCreditTransferTransactionInformation10();
|
||||
cdtTrfTxInf.setPmtId(pmtId);
|
||||
cdtTrfTxInf.setAmt(amt);
|
||||
cdtTrfTxInf.setCdtr(cbtr);
|
||||
cdtTrfTxInf.setCdtrAcct(cbtrAcct);
|
||||
cdtTrfTxInf.setCdtrAgt(cbtrAgt);
|
||||
cdtTrfTxInf.setRmtInf(rmtInf);
|
||||
|
||||
pmtInf.getCdtTrfTxInf().add(cdtTrfTxInf);
|
||||
}
|
||||
|
||||
// Header
|
||||
GroupHeader32 grpHdr = factory.createGroupHeader32();
|
||||
|
||||
/** Référence du message qui n'est pas utilisée comme référence fonctionnelle. */
|
||||
grpHdr.setMsgId(bankOrderSeq);
|
||||
|
||||
/**
|
||||
* CreationDateTime Definition : Date and Time at which a (group of) payment instruction(s) was
|
||||
* created by the instructing party. XML Tag : <CreDtTm> Occurrences : [1..1] Format :
|
||||
* YYYY-MM-DDThh:mm:ss
|
||||
*/
|
||||
grpHdr.setCreDtTm(
|
||||
datatypeFactory.newXMLGregorianCalendar(
|
||||
generationDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"))));
|
||||
grpHdr.setNbOfTxs(Integer.toString(nbOfLines));
|
||||
grpHdr.setCtrlSum(arithmeticTotal);
|
||||
grpHdr.setInitgPty(dbtr);
|
||||
|
||||
// Parent
|
||||
CustomerCreditTransferInitiationV03 customerCreditTransferInitiationV03 =
|
||||
factory.createCustomerCreditTransferInitiationV03();
|
||||
customerCreditTransferInitiationV03.setGrpHdr(grpHdr);
|
||||
customerCreditTransferInitiationV03.getPmtInf().add(pmtInf);
|
||||
|
||||
// Document
|
||||
Document xml = factory.createDocument();
|
||||
xml.setCstmrCdtTrfInitn(customerCreditTransferInitiationV03);
|
||||
|
||||
fileToCreate = factory.createDocument(xml);
|
||||
|
||||
return super.generateFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to fill the BIC information. If the BIC is not provided or in Iban only mode, we put
|
||||
* NOTPROVIDED value. In this case, the bank ignore the BIC and use the Iban only.
|
||||
*
|
||||
* @param finInstnId The financial instituation identification tag of the generated file.
|
||||
* @param bank The bank from which the BIC is get.
|
||||
*/
|
||||
protected void fillBic(FinancialInstitutionIdentification7 finInstnId, Bank bank) {
|
||||
|
||||
if (bankOrderFileFormat.getIbanOnly()
|
||||
|| bank == null
|
||||
|| Strings.isNullOrEmpty(bank.getCode())) {
|
||||
GenericFinancialIdentification1 genFinId = new GenericFinancialIdentification1();
|
||||
genFinId.setId(BIC_NOT_PROVIDED);
|
||||
finInstnId.setOthr(genFinId);
|
||||
} else {
|
||||
finInstnId.setBIC(bank.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder.file.transfer;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.google.inject.Inject;
|
||||
|
||||
public class BankOrderFileAFB160ICTService extends BankOrderFileAFB160Service {
|
||||
|
||||
@Inject
|
||||
public BankOrderFileAFB160ICTService(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
super(bankOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* B1. Code opération La liste des codes opération possibles est indiquée page 4 au paragraphe
|
||||
* "types de virements pouvant être émis par la clientèle". Les codes utilisés doivent faire
|
||||
* l'objet d'un accord contractuel avec la banque réceptrice.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected String getB1Area() {
|
||||
return OPERATION_TREASURY_TRANSFER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getSenderEArea() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getC11Area() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getB3Area() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,838 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankorder.file.transfer;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankOrder;
|
||||
import com.axelor.apps.bankpayment.db.BankOrderLine;
|
||||
import com.axelor.apps.bankpayment.exception.IExceptionMessage;
|
||||
import com.axelor.apps.bankpayment.service.bankorder.file.BankOrderFileService;
|
||||
import com.axelor.apps.bankpayment.service.cfonb.CfonbToolService;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.base.service.PartnerService;
|
||||
import com.axelor.exception.AxelorException;
|
||||
import com.axelor.exception.db.repo.TraceBackRepository;
|
||||
import com.axelor.i18n.I18n;
|
||||
import com.axelor.inject.Beans;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.datatype.DatatypeConfigurationException;
|
||||
|
||||
public abstract class BankOrderFileAFB160Service extends BankOrderFileService {
|
||||
|
||||
protected CfonbToolService cfonbToolService;
|
||||
protected PartnerService partnerService;
|
||||
protected final int NB_CHAR_PER_LINE = 160;
|
||||
|
||||
// Virements Ordinaires
|
||||
protected final String OPERATION_STANDARD_TRANSFER = "02";
|
||||
// Virements à vérifier
|
||||
protected final String OPERATION_TO_CHECK_TRANSFER = "29";
|
||||
// Virements Particuliers ("Aide Personnalisée au Logement", APL identifié par le n° d'émetteur
|
||||
// 900xxx)
|
||||
protected final String OPERATION_INDIVIDUAL_TRANSFER = "22";
|
||||
// Virements à Echéance "E-3" (à échanger 3 jours ouvrés avant l'échéance)
|
||||
protected final String OPERATION_SCHEDULE_E3_TRANSFER = "27";
|
||||
// Virements à Echéance "E-2" (à échanger 2 jours ouvrés avant l'échéance)
|
||||
protected final String OPERATION_SCHEDULE_E2_TRANSFER = "28";
|
||||
// Virements de Trésorerie (VSOT)
|
||||
protected final String OPERATION_TREASURY_TRANSFER = "76";
|
||||
|
||||
@Inject
|
||||
public BankOrderFileAFB160Service(BankOrder bankOrder) throws AxelorException {
|
||||
|
||||
super(bankOrder);
|
||||
|
||||
this.partnerService = Beans.get(PartnerService.class);
|
||||
this.cfonbToolService = Beans.get(CfonbToolService.class);
|
||||
fileExtension = FILE_EXTENSION_TXT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create an XML file for SEPA transfer pain.001.001.02
|
||||
*
|
||||
* @throws AxelorException
|
||||
* @throws DatatypeConfigurationException
|
||||
* @throws JAXBException
|
||||
* @throws IOException
|
||||
*/
|
||||
@Override
|
||||
public File generateFile()
|
||||
throws JAXBException, IOException, AxelorException, DatatypeConfigurationException {
|
||||
|
||||
List<String> records = Lists.newArrayList();
|
||||
|
||||
records.add(this.createSenderRecord());
|
||||
|
||||
for (BankOrderLine bankOrderLine : bankOrderLineList) {
|
||||
|
||||
records.add(this.createDetailRecord(bankOrderLine));
|
||||
|
||||
if (this.useOptionalFurtherInformationRecord(bankOrderLine)) {
|
||||
records.add(this.createOptionalFurtherInformationRecord(bankOrderLine));
|
||||
}
|
||||
}
|
||||
|
||||
records.add(this.createTotalRecord());
|
||||
|
||||
fileToCreate = records;
|
||||
|
||||
return super.generateFile();
|
||||
}
|
||||
|
||||
protected boolean useOptionalFurtherInformationRecord(BankOrderLine bankOrderLine) {
|
||||
|
||||
if (Strings.isNullOrEmpty(bankOrderLine.getPaymentReasonLine1())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* B1. Code opération La liste des codes opération possibles est indiquée page 4 au paragraphe
|
||||
* "types de virements pouvant être émis par la clientèle". Les codes utilisés doivent faire
|
||||
* l'objet d'un accord contractuel avec la banque réceptrice.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
abstract String getB1Area();
|
||||
|
||||
/**
|
||||
* B3. Numéro d'émetteur Attribué par la banque du donneur d'ordre (ou numéro d'identification
|
||||
* pour le Virement particulier code 22). Pour le Virement d'APL il est constitué de la façon
|
||||
* suivante : • positions 13 à 15 = 900 pour l'APL • positions 16 à 17 = numéro de département de
|
||||
* la Caisse émettrice (alphanumérique) • position 18 = rang de la Caisse dans le département (1 à
|
||||
* 9 pour les CAF, 0 pour le régime agricole)
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
abstract String getB3Area();
|
||||
|
||||
/**
|
||||
* C1-1. Code " CCD " (comportement en cas de décalage) Utilisé pour le Virement "E-3" code
|
||||
* opération 27 • 0 ou blanc = pas d'instruction • 6 = maintien de l'échéance (transformation du
|
||||
* virement en "E-2") • 7 = maintien de l'anticipation Pour les autres Virements cette zone n'est
|
||||
* pas utilisée.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
abstract String getC11Area();
|
||||
|
||||
/**
|
||||
* C1-3. Date Facultative mais recommandée pour les Virements ordinaires, particuliers et de
|
||||
* trésorerie : date demandée pour le règlement interbancaire. Obligatoire pour les Virements à
|
||||
* échéance : date d'échéance demandée.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected String getSenderC13Area() {
|
||||
|
||||
int year = this.bankOrderDate.getYear();
|
||||
|
||||
return this.bankOrderDate.format(DateTimeFormatter.ofPattern("ddMM"))
|
||||
+ (String.valueOf(year).substring(3));
|
||||
}
|
||||
|
||||
/**
|
||||
* E. Identifiant du donneur d'ordre Dans le cas d'utilisation de cet identifiant cette zone se
|
||||
* décompose de la façon suivante : 1 caractère (position 103) signe recognitif = ")" signalant la
|
||||
* présence d'un code identifiant et d'un identifiant 1 caractère (position 104) code identifiant
|
||||
* : • 1 = SIRET • 2 = AUTRE 14 caractères (positions 105 à 118) identifiant donneur d'ordre
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
abstract String getSenderEArea();
|
||||
|
||||
/**
|
||||
* D1. Domiciliation ¾ Si le compte du bénéficiaire est un compte de résident : Désignation en
|
||||
* clair de la banque et du guichet domiciliataires. Informations figurant sur le RIB du
|
||||
* bénéficiaire. Cette information est optionnelle, mais lorsque la zone est utilisée elle doit
|
||||
* être cadrée à gauche. ¾ Si le compte du bénéficiaire est un compte de non résident : ♦ Pour les
|
||||
* Virements de Salaires, Pensions et Prestations Assimilées, la zone D1 se décompose de la façon
|
||||
* suivante : D1-1. (20 caractères) positions 55 à 74 pour indiquer la domiciliation D1-2. (4
|
||||
* caractères) positions 75 à 78 • 1 caractère : Code nature économique pouvant prendre les
|
||||
* valeurs, 5 = salaires transférés par des employeurs du secteur officiel 6 = salaires transférés
|
||||
* par des employeurs privés 7 = autres rémunérations du travail 8 = pensions, retraites et
|
||||
* prestations sociales • 3 caractères : identification géographique du pays de résidence du
|
||||
* bénéficiaire du Virement. Code géonomenclature de la CEE (liste de codes pays fournie par la
|
||||
* Banque de France) ♦ Pour la Déclaration à la Balance des Paiements, cette zone D1 se décompose
|
||||
* de la façon suivante : D1-1. (9 caractères) positions 55 à 63 numéro SIREN du résident D1-2.
|
||||
* (15 caractères) positions 64 à 78 : pour indiquer la domiciliation la zone D2 se décompose en 4
|
||||
* sous zones : D2-1. (1 caractère) position 79, code type de déclaration D2-2. (3 caractères)
|
||||
* positions 80 à 82, code nature économique D2-3. (3 caractères) positions 83 à 85, code pays
|
||||
* D2-4. (1 caractère) position 86, zone réservée
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected String getDetailD1Area(BankOrderLine bankOrderLine) throws AxelorException {
|
||||
|
||||
if (bankOrderLine.getReceiverBankDetails().getBankAddress() == null) {
|
||||
throw new AxelorException(
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_RECEIVER_BANK_DETAILS_MISSING_BANK_ADDRESS),
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD);
|
||||
}
|
||||
return bankOrderLine.getReceiverBankDetails().getBankAddress().getAddress();
|
||||
}
|
||||
|
||||
protected String getDetailD2Area(BankOrderLine bankOrderLine) {
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* E. Montant Exprimé en "centimes" (00 s'il y a lieu) cadré à droite, non signé, complété
|
||||
* éventuellement à gauche par des zéros. Le montant est nul (à zéro) pour les virements à
|
||||
* vérifier
|
||||
*
|
||||
* @param bankOrderLine
|
||||
* @return
|
||||
*/
|
||||
protected BigDecimal getDetailEAreaAmount(BankOrderLine bankOrderLine) {
|
||||
|
||||
if (getB1Area().equals(OPERATION_TO_CHECK_TRANSFER)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return bankOrderLine.getBankOrderAmount();
|
||||
}
|
||||
|
||||
/**
|
||||
* F. Libellé Zone à la disposition du donneur d'ordre pour l'indication d'un libellé au
|
||||
* bénéficiaire dans le cadre d'un accord bilatéral entre le donneur d'ordre et sa banque. A
|
||||
* partir du premier novembre 2004 la banque du donneur d'ordre acheminera sans altération au
|
||||
* moins les 30 premiers caractères de cette zone jusqu'à la banque du bénéficiaire. Cette zone
|
||||
* peut être structurée de la façon suivante, afin de permettre au bénéficiaire du virement de
|
||||
* l'identifier, en tant que "REFERENCE DE L'OPERATION". Elle se décompose de la façon suivante :
|
||||
* F1. (1 caractère) position 119 = ")" F2. (12 caractères) positions 120 à 131 - Référence
|
||||
* commerciale F3. (18 caractères) positions 132 à 149 - A la disposition du donneur d'ordre
|
||||
*
|
||||
* <p>Pour les Virements Particuliers d'APL, cette zone se décompose de la façon suivante : • 13
|
||||
* caractères : Référence numéro de dossier (idem certificat de prêt) • 1 caractère : Rang de
|
||||
* l'échéance du prêt (*) • 1 caractère : Mois de l'échéance valeurs = A = janvier B = février C =
|
||||
* mars ......... • 1 caractère : Mois d'APL payé à l'établissement prêteur (*) Valeur Sans compte
|
||||
* de trésorerie Avec compte de trésorerie "1" échéance du 5 échéance du 7 au 11 "2" échéance du
|
||||
* 10 échéance du 12 au 26 "3" échéance du 25 échéance du 27 au 6
|
||||
*
|
||||
* <p>(en cas de rappel ces deux dernières positions comportent les lettres "RA")
|
||||
*
|
||||
* <p>• 15 caractères : Numéro de l'allocataire
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected String getDetailFArea(BankOrderLine bankOrderLine) {
|
||||
|
||||
return bankOrderLine.getReceiverLabel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a sender record for national transfer AFB160
|
||||
*
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
*/
|
||||
protected String createSenderRecord() throws AxelorException {
|
||||
|
||||
try {
|
||||
// Zone A : Code enregistrement
|
||||
String senderRecord =
|
||||
cfonbToolService.createZone(
|
||||
"A", "03", cfonbToolService.STATUS_MANDATORY, cfonbToolService.FORMAT_NUMERIC, 2);
|
||||
|
||||
// Zone B1 : Code opération
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B1",
|
||||
getB1Area(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
2);
|
||||
|
||||
// Zone B2 : Zone réservée
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B2", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 8);
|
||||
|
||||
// Zone B3 : Numéro d'émetteur ou d'identification pour le virement particulier code 22
|
||||
// (Virement APL)
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B3",
|
||||
getB3Area(),
|
||||
cfonbToolService.STATUS_DEPENDENT,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
6);
|
||||
|
||||
// Zone C1-1 : Code CCD (virement à échéance "E-3")
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"C1-1",
|
||||
getC11Area(),
|
||||
cfonbToolService.STATUS_DEPENDENT,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
1);
|
||||
|
||||
// Zone C1-2 : Zone réservée
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"C1-2",
|
||||
"",
|
||||
cfonbToolService.STATUS_NOT_USED,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
6);
|
||||
|
||||
// Zone C1-3 : Date (JJMMA)
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"C1-3",
|
||||
getSenderC13Area(),
|
||||
cfonbToolService.STATUS_DEPENDENT,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
5);
|
||||
|
||||
// Zone C2 : Nom/Raison sociale du donneur d'ordre
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("C2 - Company name"),
|
||||
senderCompany.getName(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
24);
|
||||
|
||||
// Zone D1-1 : Référence de la remise (à blanc ou a zéro si non utilisée)
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("D1-1 - Bank order sequence"),
|
||||
bankOrderSeq,
|
||||
cfonbToolService.STATUS_OPTIONAL,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
7);
|
||||
|
||||
// Zone D1-2 : Zone réservée
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"D1-2",
|
||||
"",
|
||||
cfonbToolService.STATUS_NOT_USED,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
17);
|
||||
|
||||
// Zone D2-1 : Zone réservée
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"D2-1",
|
||||
"",
|
||||
cfonbToolService.STATUS_NOT_USED,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
2);
|
||||
|
||||
// Zone D2-2 : Code monnaie
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"D2-2", "E", cfonbToolService.STATUS_MANDATORY, cfonbToolService.FORMAT_ALPHA, 1);
|
||||
|
||||
// Zone D2-3 : Zone réservée
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"D2-3",
|
||||
"",
|
||||
cfonbToolService.STATUS_NOT_USED,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
5);
|
||||
|
||||
// Zone D3 : Code guichet de la banque du donneur d'ordre
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("D3 - Sort code"),
|
||||
senderBankDetails.getSortCode(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
5);
|
||||
|
||||
// Zone D4 : Numéro de compte du donneur d'ordre
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("D4 - Account number"),
|
||||
senderBankDetails.getAccountNbr(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
11);
|
||||
|
||||
// Zone E : Identifiant du donneur d'ordre
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"E",
|
||||
getSenderEArea(),
|
||||
cfonbToolService.STATUS_OPTIONAL,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
16);
|
||||
|
||||
// Zone F : Zone réservée
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"F", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 31);
|
||||
|
||||
// Zone G1 : Code établissement de la banque du donneur d'ordre
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("G1 - Bank code"),
|
||||
senderBankDetails.getBankCode(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
5);
|
||||
|
||||
// Zone G2 : Zone réservée
|
||||
senderRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"G2", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 6);
|
||||
|
||||
cfonbToolService.toUpperCase(senderRecord);
|
||||
|
||||
cfonbToolService.testLength(senderRecord, NB_CHAR_PER_LINE);
|
||||
|
||||
return senderRecord;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new AxelorException(
|
||||
e,
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_WRONG_SENDER_RECORD) + ": " + e.getMessage(),
|
||||
bankOrderSeq);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a recipient record for national transfer AFB160
|
||||
*
|
||||
* @param bankOrderLine
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
*/
|
||||
protected String createDetailRecord(BankOrderLine bankOrderLine) throws AxelorException {
|
||||
|
||||
try {
|
||||
BankDetails receiverBankDetails = bankOrderLine.getReceiverBankDetails();
|
||||
|
||||
// Zone A : Code enregistrement
|
||||
String detailRecord =
|
||||
cfonbToolService.createZone(
|
||||
"A", "06", cfonbToolService.STATUS_MANDATORY, cfonbToolService.FORMAT_NUMERIC, 2);
|
||||
|
||||
// Zone B1 : Code opération
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B1",
|
||||
getB1Area(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
2);
|
||||
|
||||
// Zone B2 : Zone réservée
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B2", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 8);
|
||||
|
||||
// Zone B3 : Numéro d'émetteur ou d'identification pour le virement particulier code 22
|
||||
// (Virement APL)
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B3",
|
||||
getB3Area(),
|
||||
cfonbToolService.STATUS_DEPENDENT,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
6);
|
||||
|
||||
// Zone C1 : Référence
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("C1 - Sequence"),
|
||||
bankOrderLine.getSequence(),
|
||||
cfonbToolService.STATUS_OPTIONAL,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
12);
|
||||
|
||||
// Zone C2 : Nom/Raison sociale du bénéficiaire
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("C2 - Receiver company name"),
|
||||
bankOrderLine.getReceiverCompany().getName(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
24);
|
||||
|
||||
// Zone D1 : Domiciliation
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("D1 - Bank address"),
|
||||
getDetailD1Area(bankOrderLine),
|
||||
cfonbToolService.STATUS_DEPENDENT,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
24);
|
||||
|
||||
// Zone D2 : Déclaration à la balance des paiements
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"D2",
|
||||
getDetailD2Area(bankOrderLine),
|
||||
cfonbToolService.STATUS_DEPENDENT,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
8);
|
||||
|
||||
// Zone D3 : Code guichet de la banque qui tient le compte du bénéficiaire
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("D3 - Sort code"),
|
||||
receiverBankDetails.getSortCode(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
5);
|
||||
|
||||
// Zone D4 : Numéro de compte du bénéficiaire
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("D4 - Account number"),
|
||||
receiverBankDetails.getAccountNbr(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
11);
|
||||
|
||||
// Zone E : Montant du virement
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("E - Bank order amount"),
|
||||
getDetailEAreaAmount(bankOrderLine),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
16);
|
||||
|
||||
// Zone F : Libellé
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("F - Receiver label"),
|
||||
getDetailFArea(bankOrderLine),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
31);
|
||||
|
||||
// Zone G1 : Code établissement de la banque qui tient le compte du bénéficiaire
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"G1",
|
||||
receiverBankDetails.getBankCode(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
5);
|
||||
|
||||
// Zone G2 : Zone réservée
|
||||
detailRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"G2", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 6);
|
||||
|
||||
cfonbToolService.toUpperCase(detailRecord);
|
||||
|
||||
cfonbToolService.testLength(detailRecord, NB_CHAR_PER_LINE);
|
||||
|
||||
return detailRecord;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new AxelorException(
|
||||
e,
|
||||
bankOrderLine,
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_WRONG_MAIN_DETAIL_RECORD) + ": " + e.getMessage(),
|
||||
bankOrderLine.getSequence());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create an optional further information record for national transfer AFB160
|
||||
*
|
||||
* @param bankOrderLine
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
*/
|
||||
protected String createOptionalFurtherInformationRecord(BankOrderLine bankOrderLine)
|
||||
throws AxelorException {
|
||||
|
||||
try {
|
||||
BankDetails receiverBankDetails = bankOrderLine.getReceiverBankDetails();
|
||||
|
||||
// Zone A : Code enregistrement
|
||||
String totalRecord =
|
||||
cfonbToolService.createZone(
|
||||
"A", "07", cfonbToolService.STATUS_MANDATORY, cfonbToolService.FORMAT_NUMERIC, 2);
|
||||
|
||||
// Zone B1 : Code opération
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B1",
|
||||
getB1Area(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
2);
|
||||
|
||||
// Zone B2 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B2", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 8);
|
||||
|
||||
// Zone B3 : Numéro d'émetteur ou d'identification pour le virement particulier code 22
|
||||
// (Virement APL)
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B3",
|
||||
getB3Area(),
|
||||
cfonbToolService.STATUS_DEPENDENT,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
6);
|
||||
|
||||
// Zone C1 : Référence
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("C1 - Sequence"),
|
||||
bankOrderLine.getSequence(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
12);
|
||||
|
||||
// Zone C2 : Nom/Raison sociale du bénéficiaire
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("C2 - Receiver company name"),
|
||||
bankOrderLine.getReceiverCompany().getName(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
24);
|
||||
|
||||
// Zone D1 : Domiciliation
|
||||
if (bankOrderLine.getReceiverBankDetails().getBankAddress() == null) {
|
||||
throw new AxelorException(
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_RECEIVER_BANK_DETAILS_MISSING_BANK_ADDRESS),
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD);
|
||||
}
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("D1 - Bank address"),
|
||||
receiverBankDetails.getBankAddress().getAddress(),
|
||||
cfonbToolService.STATUS_DEPENDENT,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
24);
|
||||
|
||||
// Zone D2 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"D2", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 8);
|
||||
|
||||
// Zone D3 : Code guichet de la banque qui tient le compte du bénéficiaire
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("D3 - Sort code"),
|
||||
receiverBankDetails.getSortCode(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
5);
|
||||
|
||||
// Zone D4 : Numéro de compte du bénéficiaire
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("D4 - Account number"),
|
||||
receiverBankDetails.getAccountNbr(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
11);
|
||||
|
||||
// Zone E : Montant du virement
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("E - Bank order amount"),
|
||||
bankOrderLine.getBankOrderAmount(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
16);
|
||||
|
||||
// Zone F : Libellé complémentaire
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("F - Receiver label"),
|
||||
bankOrderLine.getPaymentReasonLine1(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
31);
|
||||
|
||||
// Zone G1 : Code établissement de la banque qui tient le compte du bénéficiaire
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
I18n.get("G1 - Bank establisment code"),
|
||||
receiverBankDetails.getBankCode(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
5);
|
||||
|
||||
// Zone G2 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"G2", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 6);
|
||||
|
||||
cfonbToolService.toUpperCase(totalRecord);
|
||||
|
||||
cfonbToolService.testLength(totalRecord, NB_CHAR_PER_LINE);
|
||||
|
||||
return totalRecord;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new AxelorException(
|
||||
e,
|
||||
bankOrderLine,
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_WRONG_FURTHER_INFORMATION_DETAIL_RECORD)
|
||||
+ ": "
|
||||
+ e.getMessage(),
|
||||
bankOrderLine.getSequence());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create a total record for national transfer AFB160
|
||||
*
|
||||
* @param company
|
||||
* @param dateTime
|
||||
* @return
|
||||
* @throws AxelorException
|
||||
*/
|
||||
protected String createTotalRecord() throws AxelorException {
|
||||
|
||||
try {
|
||||
// Zone A : Code enregistrement
|
||||
String totalRecord =
|
||||
cfonbToolService.createZone(
|
||||
"A", "08", cfonbToolService.STATUS_MANDATORY, cfonbToolService.FORMAT_NUMERIC, 2);
|
||||
|
||||
// Zone B1 : Code opération
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B1",
|
||||
getB1Area(),
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
2);
|
||||
|
||||
// Zone B2 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B2", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 8);
|
||||
|
||||
// Zone B3 : Numéro d'émetteur ou d'identification pour le virement particulier code 22
|
||||
// (Virement APL)
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"B3",
|
||||
getB3Area(),
|
||||
cfonbToolService.STATUS_DEPENDENT,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
6);
|
||||
|
||||
// Zone C1 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"C1",
|
||||
"",
|
||||
cfonbToolService.STATUS_NOT_USED,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
12);
|
||||
|
||||
// Zone C2 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"C2",
|
||||
"",
|
||||
cfonbToolService.STATUS_NOT_USED,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
24);
|
||||
|
||||
// Zone D1 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"D1",
|
||||
"",
|
||||
cfonbToolService.STATUS_NOT_USED,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
24);
|
||||
|
||||
// Zone D2 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"D2", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 8);
|
||||
|
||||
// Zone D3 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"D3", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 5);
|
||||
|
||||
// Zone D4 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"D4",
|
||||
"",
|
||||
cfonbToolService.STATUS_NOT_USED,
|
||||
cfonbToolService.FORMAT_ALPHA_NUMERIC,
|
||||
11);
|
||||
|
||||
// Zone E : Montant du virement
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"E",
|
||||
arithmeticTotal,
|
||||
cfonbToolService.STATUS_MANDATORY,
|
||||
cfonbToolService.FORMAT_NUMERIC,
|
||||
16);
|
||||
|
||||
// Zone F : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"F", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 31);
|
||||
|
||||
// Zone G1 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"G1", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 5);
|
||||
|
||||
// Zone G2 : Zone réservée
|
||||
totalRecord +=
|
||||
cfonbToolService.createZone(
|
||||
"G2", "", cfonbToolService.STATUS_NOT_USED, cfonbToolService.FORMAT_ALPHA_NUMERIC, 6);
|
||||
|
||||
cfonbToolService.toUpperCase(totalRecord);
|
||||
|
||||
cfonbToolService.testLength(totalRecord, NB_CHAR_PER_LINE);
|
||||
|
||||
return totalRecord;
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new AxelorException(
|
||||
e,
|
||||
TraceBackRepository.CATEGORY_MISSING_FIELD,
|
||||
I18n.get(IExceptionMessage.BANK_ORDER_WRONG_TOTAL_RECORD) + ": " + e.getMessage(),
|
||||
bankOrderSeq);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Axelor Business Solutions
|
||||
*
|
||||
* Copyright (C) 2019 Axelor (<http://axelor.com>).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.axelor.apps.bankpayment.service.bankreconciliation;
|
||||
|
||||
import com.axelor.apps.bankpayment.db.BankReconciliation;
|
||||
import com.axelor.apps.bankpayment.db.BankStatement;
|
||||
import com.axelor.apps.bankpayment.db.repo.BankReconciliationRepository;
|
||||
import com.axelor.apps.base.db.BankDetails;
|
||||
import com.axelor.apps.base.db.Company;
|
||||
import com.axelor.apps.base.db.Currency;
|
||||
import com.axelor.apps.base.db.repo.CompanyRepository;
|
||||
import com.axelor.db.JPA;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.persist.Transactional;
|
||||
import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.persistence.Query;
|
||||
|
||||
public class BankReconciliationCreateService {
|
||||
|
||||
protected BankReconciliationRepository bankReconciliationRepository;
|
||||
protected CompanyRepository companyRepository;
|
||||
|
||||
@Inject
|
||||
public BankReconciliationCreateService(
|
||||
BankReconciliationRepository bankReconciliationRepository,
|
||||
CompanyRepository companyRepository) {
|
||||
|
||||
this.bankReconciliationRepository = bankReconciliationRepository;
|
||||
this.companyRepository = companyRepository;
|
||||
}
|
||||
|
||||
@Transactional(rollbackOn = {Exception.class})
|
||||
public List<BankReconciliation> createAllFromBankStatement(BankStatement bankStatement)
|
||||
throws IOException {
|
||||
|
||||
List<BankReconciliation> bankReconciliationList = new ArrayList<>();
|
||||
|
||||
List<BankDetails> bankDetailsList = getDistinctBankDetails(bankStatement);
|
||||
|
||||
if (bankDetailsList == null) {
|
||||
return bankReconciliationList;
|
||||
}
|
||||
|
||||
LocalDate fromDate = bankStatement.getFromDate();
|
||||
LocalDate toDate = bankStatement.getToDate();
|
||||
|
||||
for (BankDetails bankDetails : bankDetailsList) {
|
||||
|
||||
Company company =
|
||||
companyRepository
|
||||
.all()
|
||||
.filter("?1 member of self.bankDetailsSet", bankDetails)
|
||||
.fetchOne();
|
||||
|
||||
Currency currency = bankDetails.getCurrency();
|
||||
if (currency == null) {
|
||||
currency = company.getCurrency();
|
||||
}
|
||||
|
||||
BankReconciliation bankReconciliation =
|
||||
createBankReconciliation(company, fromDate, toDate, currency, bankDetails, bankStatement);
|
||||
bankReconciliationRepository.save(bankReconciliation);
|
||||
bankReconciliationList.add(bankReconciliation);
|
||||
}
|
||||
|
||||
return bankReconciliationList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all distinct bank details that appear on the bank statement.
|
||||
*
|
||||
* @param bankStatement
|
||||
* @return List of bank details
|
||||
*/
|
||||
protected List<BankDetails> getDistinctBankDetails(BankStatement bankStatement) {
|
||||
|
||||
Query q =
|
||||
JPA.em()
|
||||
.createQuery(
|
||||
"SELECT DISTINCT(BSL.bankDetails) FROM BankStatementLine BSL WHERE BSL.bankStatement = :bankStatement AND BSL.amountRemainToReconcile > 0");
|
||||
|
||||
q.setParameter("bankStatement", bankStatement);
|
||||
|
||||
return q.getResultList();
|
||||
}
|
||||
|
||||
public BankReconciliation createBankReconciliation(
|
||||
Company company,
|
||||
LocalDate fromDate,
|
||||
LocalDate toDate,
|
||||
Currency currency,
|
||||
BankDetails bankDetails,
|
||||
BankStatement bankStatement)
|
||||
throws IOException {
|
||||
|
||||
BankReconciliation bankReconciliation = new BankReconciliation();
|
||||
bankReconciliation.setCompany(company);
|
||||
bankReconciliation.setFromDate(fromDate);
|
||||
bankReconciliation.setToDate(toDate);
|
||||
bankReconciliation.setCurrency(currency);
|
||||
bankReconciliation.setBankDetails(bankDetails);
|
||||
bankReconciliation.setBankStatement(bankStatement);
|
||||
bankReconciliation.setName(this.computeName(bankReconciliation));
|
||||
|
||||
return bankReconciliation;
|
||||
}
|
||||
|
||||
public String computeName(BankReconciliation bankReconciliation) {
|
||||
|
||||
String name = "";
|
||||
if (bankReconciliation.getCompany() != null) {
|
||||
name += bankReconciliation.getCompany().getCode();
|
||||
}
|
||||
if (bankReconciliation.getCurrency() != null) {
|
||||
if (name != "") {
|
||||
name += "-";
|
||||
}
|
||||
name += bankReconciliation.getCurrency().getCode();
|
||||
}
|
||||
if (bankReconciliation.getBankDetails() != null) {
|
||||
if (name != "") {
|
||||
name += "-";
|
||||
}
|
||||
name += bankReconciliation.getBankDetails().getAccountNbr();
|
||||
}
|
||||
if (bankReconciliation.getFromDate() != null) {
|
||||
if (name != "") {
|
||||
name += "-";
|
||||
}
|
||||
name += bankReconciliation.getFromDate().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
|
||||
}
|
||||
if (bankReconciliation.getToDate() != null) {
|
||||
if (name != "") {
|
||||
name += "-";
|
||||
}
|
||||
name += bankReconciliation.getToDate().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user