First commit waiting for Budget Alert

This commit is contained in:
2025-09-04 13:37:35 +01:00
commit 2d681f27f5
4563 changed files with 1061534 additions and 0 deletions

View File

@ -0,0 +1,17 @@
apply plugin: "com.axelor.app-module"
apply from: "../version.gradle"
apply {
version = openSuiteVersion
}
axelor {
title "Axelor Business Project"
description "Axelor Business Project Module"
}
dependencies {
compile project(":modules:axelor-human-resource")
compile project(":modules:axelor-contract")
}

View File

@ -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.businessproject.db.repo;
import com.axelor.apps.base.db.AppBusinessProject;
import com.axelor.apps.base.db.repo.AppBusinessProjectRepository;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.team.db.repo.TeamTaskRepository;
import com.google.common.base.Strings;
import com.google.inject.Inject;
import javax.persistence.PersistenceException;
public class AppBusinessProjectManagementRepository extends AppBusinessProjectRepository {
@Inject private TeamTaskRepository teamTaskRepo;
@Override
public AppBusinessProject save(AppBusinessProject entity) {
try {
if (!Strings.isNullOrEmpty(entity.getExculdeTaskInvoicing())) {
teamTaskRepo.all().filter(entity.getExculdeTaskInvoicing()).count();
}
return super.save(entity);
} catch (Exception e) {
TraceBackService.trace(e);
throw new PersistenceException(I18n.get(IExceptionMessage.INVALID_EXCLUDE_TASK_FILTER));
}
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.businessproject.db.repo;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.repo.InvoiceManagementRepository;
import com.axelor.inject.Beans;
public class InvoiceProjectRepository extends InvoiceManagementRepository {
@Override
public void remove(Invoice entity) {
Beans.get(InvoicingProjectRepository.class)
.all()
.filter("self.invoice.id = ?", entity.getId())
.remove();
super.remove(entity);
}
}

View File

@ -0,0 +1,37 @@
/*
* 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.businessproject.db.repo;
import com.axelor.apps.businessproject.db.InvoicingProject;
import com.axelor.i18n.I18n;
import javax.persistence.PersistenceException;
public class InvoicingProjectManagementRepository extends InvoicingProjectRepository {
@Override
public void remove(InvoicingProject entity) {
if (entity.getInvoice() != null) {
throw new PersistenceException(
I18n.get(
"Since the invoice has already been generated, it's impossible to delete this record"));
} else {
super.remove(entity);
}
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.businessproject.db.repo;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.apps.supplychain.db.repo.SaleOrderSupplychainRepository;
public class SaleOrderProjectRepository extends SaleOrderSupplychainRepository {
@Override
public SaleOrder copy(SaleOrder entity, boolean deep) {
SaleOrder copy = super.copy(entity, deep);
copy.setProject(null);
return copy;
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.businessproject.db.repo;
import com.axelor.apps.hr.db.repo.TeamTaskHRRepository;
import com.axelor.team.db.TeamTask;
public class TeamTaskBusinessProjectRepository extends TeamTaskHRRepository {
@Override
public TeamTask copy(TeamTask entity, boolean deep) {
entity.setSaleOrderLine(null);
entity.setInvoiceLine(null);
return super.copy(entity, deep);
}
}

View File

@ -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.businessproject.exception;
/**
* Interface of Exceptions. Enum all exception of axelor-account.
*
* @author dubaux
*/
public interface IExceptionMessage {
static final String FOLDER_TEMPLATE = /*$$(*/ "You must add a sale order template" /*)*/;
static final String INVOICING_PROJECT_EMPTY = /*$$(*/
"You haven't select any element to invoice" /*)*/;
static final String INVOICING_PROJECT_PROJECT = /*$$(*/ "You must select a project/task" /*)*/;
static final String INVOICING_PROJECT_PROJECT_PARTNER = /*$$(*/
"There is no customer for this project/task" /*)*/;
static final String INVOICING_PROJECT_PROJECT_PRODUCT = /*$$(*/
"You haven't select a product to invoice for the task %s" /*)*/;
static final String INVOICING_PROJECT_PROJECT_COMPANY = /*$$(*/
"You haven't select a company on the main project" /*)*/;
static final String SALE_ORDER_NO_PROJECT = /*$$(*/ "No Project selected" /*)*/;
static final String SALE_ORDER_NO_LINES = /*$$(*/ "No Line can be used for tasks" /*)*/;
static final String SALE_ORDER_NO_TYPE_GEN_PROJECT = /*$$(*/
"No type of generation project has been selected" /*)*/;
static final String SALE_ORDER_BUSINESS_PROJECT = /*$$(*/
"The project is configured to be alone" /*)*/;
static final String JOB_COSTING_APP = /*$$(*/ "Job costing" /*)*/;
String FACTORY_NO_FOUND = /*$$(*/ "Factory not found this type of generator" /*)*/;
String FACTORY_FILL_WITH_PROJECT_ALONE = /*$$(*/
"You can't fill a project with the strategy Project Alone." /*)*/;
static final String NO_PROJECT_IN_CONTEXT = /*$$(*/ "No project found in context" /*)*/;
static final String LINES_NOT_SELECTED = /*$$(*/ "Please select lines" /*)*/;
static final String SALE_ORDER_GENERATE_FILL_PROJECT_ERROR_1 = /*$$(*/
"Products must be Service type and Method of Supply Produce." /*)*/;
static final String SALE_ORDER_GENERATE_FILL_PROJECT_ERROR_2 = /*$$(*/
"Please complete the order lines with at least one product type 'Service' and the supply mode 'Produce'" /*)*/;
static final String INVALID_EXCLUDE_TASK_FILTER = /*$$(*/
"Invalid exclude task for invoicing filter" /*)*/;
static final String BATCH_TASK_UPDATION_1 = /*$$(*/ "Task %s" /*)*/;
static final String BATCH_TASK_UPDATION_2 = /*$$(*/ "Tasks updation completed : " /*)*/;
static final String BATCH_INVOICING_PROJECT_1 = /*$$(*/ "Project %s" /*)*/;
static final String BATCH_INVOICING_PROJECT_2 = /*$$(*/ "Generated invoicing project" /*)*/;
}

View File

@ -0,0 +1,76 @@
/*
* 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.businessproject.mobile;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.auth.AuthUtils;
import com.axelor.auth.db.User;
import com.axelor.inject.Beans;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BusinessProjectMobileController {
/*
* This method is used in mobile application.
* It was in ProjectTaskBusinessServiceImpl
* @param request
* @param response
*
* POST /open-suite-webapp/ws/action/com.axelor.apps.businessproject.mobile.BusinessProjectMobileController:getProjects
* Content-Type: application/json
*
* URL: com.axelor.apps.businessproject.mobile.BusinessProjectMobileController:getProjects
* fields: no field
*
* payload:
* { "data": {
* "action": "com.axelor.apps.businessproject.mobile.BusinessProjectMobileController:getProjects"
* } }
*/
public void getProjects(ActionRequest request, ActionResponse response) {
List<Map<String, String>> dataList = new ArrayList<Map<String, String>>();
try {
User user = AuthUtils.getUser();
if (user != null) {
List<Project> projectList =
Beans.get(ProjectRepository.class).all().filter("self.imputable = true").fetch();
for (Project project : projectList) {
if ((project.getMembersUserSet() != null && project.getMembersUserSet().contains(user))
|| user.equals(project.getAssignedTo())) {
Map<String, String> map = new HashMap<String, String>();
map.put("name", project.getName());
map.put("id", project.getId().toString());
dataList.add(map);
}
}
}
response.setData(dataList);
response.setTotal(dataList.size());
} catch (Exception e) {
response.setStatus(-1);
response.setError(e.getMessage());
}
}
}

View File

@ -0,0 +1,129 @@
/*
* 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.businessproject.module;
import com.axelor.app.AxelorModule;
import com.axelor.apps.account.db.repo.InvoiceManagementRepository;
import com.axelor.apps.bankpayment.service.invoice.payment.InvoicePaymentValidateServiceBankPayImpl;
import com.axelor.apps.base.db.repo.AppBusinessProjectRepository;
import com.axelor.apps.businessproject.db.repo.AppBusinessProjectManagementRepository;
import com.axelor.apps.businessproject.db.repo.InvoiceProjectRepository;
import com.axelor.apps.businessproject.db.repo.InvoicingProjectManagementRepository;
import com.axelor.apps.businessproject.db.repo.InvoicingProjectRepository;
import com.axelor.apps.businessproject.db.repo.SaleOrderProjectRepository;
import com.axelor.apps.businessproject.db.repo.TeamTaskBusinessProjectRepository;
import com.axelor.apps.businessproject.service.ContractLineServiceProjectImpl;
import com.axelor.apps.businessproject.service.ExpenseLineProjectService;
import com.axelor.apps.businessproject.service.ExpenseLineProjectServiceImpl;
import com.axelor.apps.businessproject.service.ExpenseServiceProjectImpl;
import com.axelor.apps.businessproject.service.InvoiceLineProjectService;
import com.axelor.apps.businessproject.service.InvoiceLineProjectServiceImpl;
import com.axelor.apps.businessproject.service.InvoicePaymentValidateProjectServiceImpl;
import com.axelor.apps.businessproject.service.InvoiceServiceProjectImpl;
import com.axelor.apps.businessproject.service.ProductTaskTemplateService;
import com.axelor.apps.businessproject.service.ProductTaskTemplateServiceImpl;
import com.axelor.apps.businessproject.service.ProjectBusinessService;
import com.axelor.apps.businessproject.service.ProjectBusinessServiceImpl;
import com.axelor.apps.businessproject.service.ProjectContractServiceImpl;
import com.axelor.apps.businessproject.service.ProjectFolderService;
import com.axelor.apps.businessproject.service.ProjectFolderServiceImpl;
import com.axelor.apps.businessproject.service.ProjectPurchaseServiceImpl;
import com.axelor.apps.businessproject.service.ProjectStockMoveInvoiceServiceImpl;
import com.axelor.apps.businessproject.service.PurchaseOrderInvoiceProjectServiceImpl;
import com.axelor.apps.businessproject.service.PurchaseOrderLineProjectService;
import com.axelor.apps.businessproject.service.PurchaseOrderLineServiceProjectImpl;
import com.axelor.apps.businessproject.service.SaleOrderInvoiceProjectServiceImpl;
import com.axelor.apps.businessproject.service.SaleOrderLineProjectService;
import com.axelor.apps.businessproject.service.SaleOrderLineProjectServiceImpl;
import com.axelor.apps.businessproject.service.TeamTaskBusinessProjectService;
import com.axelor.apps.businessproject.service.TeamTaskBusinessProjectServiceImpl;
import com.axelor.apps.businessproject.service.TimesheetLineBusinessService;
import com.axelor.apps.businessproject.service.TimesheetLineProjectServiceImpl;
import com.axelor.apps.businessproject.service.TimesheetProjectService;
import com.axelor.apps.businessproject.service.TimesheetProjectServiceImpl;
import com.axelor.apps.businessproject.service.WorkflowCancelServiceProjectImpl;
import com.axelor.apps.businessproject.service.WorkflowValidationServiceProjectImpl;
import com.axelor.apps.businessproject.service.WorkflowVentilationProjectServiceImpl;
import com.axelor.apps.businessproject.service.app.AppBusinessProjectService;
import com.axelor.apps.businessproject.service.app.AppBusinessProjectServiceImpl;
import com.axelor.apps.contract.service.ContractLineServiceImpl;
import com.axelor.apps.contract.service.ContractServiceImpl;
import com.axelor.apps.hr.db.repo.TeamTaskHRRepository;
import com.axelor.apps.hr.service.expense.ExpenseServiceImpl;
import com.axelor.apps.hr.service.timesheet.TimesheetLineServiceImpl;
import com.axelor.apps.hr.service.timesheet.TimesheetServiceImpl;
import com.axelor.apps.project.service.ProjectServiceImpl;
import com.axelor.apps.project.service.TeamTaskProjectServiceImpl;
import com.axelor.apps.supplychain.db.repo.SaleOrderSupplychainRepository;
import com.axelor.apps.supplychain.service.InvoiceLineSupplychainService;
import com.axelor.apps.supplychain.service.PurchaseOrderInvoiceServiceImpl;
import com.axelor.apps.supplychain.service.PurchaseOrderLineServiceSupplychainImpl;
import com.axelor.apps.supplychain.service.SaleOrderInvoiceServiceImpl;
import com.axelor.apps.supplychain.service.SaleOrderLineServiceSupplyChainImpl;
import com.axelor.apps.supplychain.service.SaleOrderPurchaseServiceImpl;
import com.axelor.apps.supplychain.service.StockMoveInvoiceServiceImpl;
import com.axelor.apps.supplychain.service.invoice.InvoiceServiceSupplychainImpl;
import com.axelor.apps.supplychain.service.workflow.WorkflowCancelServiceSupplychainImpl;
import com.axelor.apps.supplychain.service.workflow.WorkflowValidationServiceSupplychainImpl;
import com.axelor.apps.supplychain.service.workflow.WorkflowVentilationServiceSupplychainImpl;
public class BusinessProjectModule extends AxelorModule {
@Override
protected void configure() {
bind(SaleOrderInvoiceServiceImpl.class).to(SaleOrderInvoiceProjectServiceImpl.class);
bind(PurchaseOrderInvoiceServiceImpl.class).to(PurchaseOrderInvoiceProjectServiceImpl.class);
bind(TimesheetServiceImpl.class).to(TimesheetProjectServiceImpl.class);
bind(TimesheetProjectService.class).to(TimesheetProjectServiceImpl.class);
bind(TimesheetLineServiceImpl.class).to(TimesheetLineProjectServiceImpl.class);
bind(ExpenseServiceImpl.class).to(ExpenseServiceProjectImpl.class);
bind(ProjectServiceImpl.class).to(ProjectBusinessServiceImpl.class);
bind(ProjectBusinessService.class).to(ProjectBusinessServiceImpl.class);
bind(InvoicingProjectRepository.class).to(InvoicingProjectManagementRepository.class);
bind(AppBusinessProjectService.class).to(AppBusinessProjectServiceImpl.class);
bind(InvoiceServiceSupplychainImpl.class).to(InvoiceServiceProjectImpl.class);
bind(TeamTaskProjectServiceImpl.class).to(TeamTaskBusinessProjectServiceImpl.class);
bind(TeamTaskBusinessProjectService.class).to(TeamTaskBusinessProjectServiceImpl.class);
bind(SaleOrderSupplychainRepository.class).to(SaleOrderProjectRepository.class);
bind(ProductTaskTemplateService.class).to(ProductTaskTemplateServiceImpl.class);
bind(StockMoveInvoiceServiceImpl.class).to(ProjectStockMoveInvoiceServiceImpl.class);
bind(SaleOrderPurchaseServiceImpl.class).to(ProjectPurchaseServiceImpl.class);
bind(PurchaseOrderLineServiceSupplychainImpl.class)
.to(PurchaseOrderLineServiceProjectImpl.class);
bind(SaleOrderLineProjectService.class).to(SaleOrderLineProjectServiceImpl.class);
bind(PurchaseOrderLineProjectService.class).to(PurchaseOrderLineServiceProjectImpl.class);
bind(ExpenseLineProjectService.class).to(ExpenseLineProjectServiceImpl.class);
bind(InvoiceLineProjectService.class).to(InvoiceLineProjectServiceImpl.class);
bind(InvoiceManagementRepository.class).to(InvoiceProjectRepository.class);
bind(WorkflowVentilationServiceSupplychainImpl.class)
.to(WorkflowVentilationProjectServiceImpl.class);
bind(TimesheetLineBusinessService.class).to(TimesheetLineProjectServiceImpl.class);
bind(WorkflowValidationServiceSupplychainImpl.class)
.to(WorkflowValidationServiceProjectImpl.class);
bind(WorkflowCancelServiceSupplychainImpl.class).to(WorkflowCancelServiceProjectImpl.class);
bind(TeamTaskHRRepository.class).to(TeamTaskBusinessProjectRepository.class);
bind(SaleOrderLineServiceSupplyChainImpl.class).to(SaleOrderLineProjectServiceImpl.class);
bind(InvoiceLineSupplychainService.class).to(InvoiceLineProjectServiceImpl.class);
bind(ContractServiceImpl.class).to(ProjectContractServiceImpl.class);
bind(ContractLineServiceImpl.class).to(ContractLineServiceProjectImpl.class);
bind(AppBusinessProjectRepository.class).to(AppBusinessProjectManagementRepository.class);
bind(InvoicePaymentValidateServiceBankPayImpl.class)
.to(InvoicePaymentValidateProjectServiceImpl.class);
bind(ProjectFolderService.class).to(ProjectFolderServiceImpl.class);
}
}

View File

@ -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.businessproject.report;
public interface IReport {
public static final String PROJECT = "Project.rptdesign";
public static final String INVOICE_ANNEX = "InvoiceAnnex.rptdesign";
public static final String PLANNIF_AND_COST = "PlannificationAndCost.rptdesign";
public static final String INVOICING_PROJECT_ANNEX = "InvoicingProjectAnnex.rptdesign";
}

View File

@ -0,0 +1,211 @@
/*
* 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.businessproject.report;
public interface ITranslation {
public static final String PROJECT_TITLE = /*$$(*/ "Project.title"; /*)*/
public static final String PROJECT_CUSTOMER = /*$$(*/ "Project.customer"; /*)*/
public static final String PROJECT_CURRENCY = /*$$(*/ "Project.currency"; /*)*/
public static final String PROJECT_INITIAL = /*$$(*/ "Project.initial"; /*)*/
public static final String PROJECT_SO = /*$$(*/ "Project.salesOrders"; /*)*/
public static final String PROJECT_TASK = /*$$(*/ "Project.tasks"; /*)*/
public static final String PROJECT_TASK_NAME = /*$$(*/ "Project.taskName"; /*)*/
public static final String PROJECT_END_DATE = /*$$(*/ "Project.endDate"; /*)*/
public static final String PROJECT_PROGRESS = /*$$(*/ "Project.progress"; /*)*/
public static final String PROJECT_SO_NO = /*$$(*/ "Project.salesOrderNumber"; /*)*/
public static final String PROJECT_PO_NO = /*$$(*/ "Project.purchaseOrderNumber"; /*)*/
public static final String PROJECT_DATE = /*$$(*/ "Project.date"; /*)*/
public static final String PROJECT_SALES = /*$$(*/ "Project.sales"; /*)*/
public static final String PROJECT_COSTS = /*$$(*/ "Project.costs"; /*)*/
public static final String PROJECT_Margin = /*$$(*/ "Project.margin"; /*)*/
public static final String PROJECT_EXPECTED_MARGIN = /*$$(*/ "Project.expectedMargin"; /*)*/
public static final String PROJECT_EXPECTED_REVENUE = /*$$(*/ "Project.expectedRevenue"; /*)*/
public static final String PROJECT_EXPECTED_COSTS = /*$$(*/ "Project.expectedCosts"; /*)*/
public static final String PROJECT_TOTAL_SALES = /*$$(*/ "Project.totalSales"; /*)*/
public static final String PROJECT_TOTAL_TURNOVER = /*$$(*/ "Project.totalTurnover"; /*)*/
public static final String PROJECT_TOTAL_COSTS = /*$$(*/ "Project.totalCosts"; /*)*/
public static final String PROJECT_TOTAL_MARGIN = /*$$(*/ "Project.totalMargin"; /*)*/
public static final String PROJECT_INVOICED = /*$$(*/ "Project.invoiced"; /*)*/
public static final String PROJECT_TURNOVER = /*$$(*/ "Project.turnover"; /*)*/
public static final String PROJECT_SALES_INVOICE = /*$$(*/ "Project.salesInvoice"; /*)*/
public static final String PROJECT_INVOICE_NUMBER = /*$$(*/ "Project.invoiceNumber"; /*)*/
public static final String PROJECT_SUB_TYPE = /*$$(*/ "Project.subType"; /*)*/
public static final String PROJECT_AMOUNT = /*$$(*/ "Project.amount"; /*)*/
public static final String PROJECT_PURCHASE = /*$$(*/ "Project.purchase"; /*)*/
public static final String PROJECT_EXPENSE = /*$$(*/ "Project.expense"; /*)*/
public static final String PROJECT_EMPLOYEE = /*$$(*/ "Project.employee"; /*)*/
public static final String PROJECT_PLANNING = /*$$(*/ "Project.planning"; /*)*/
public static final String PROJECT_TIMESHEET = /*$$(*/ "Project.timesheet"; /*)*/
public static final String PROJECT_TOTAL_HOURS = /*$$(*/ "Project.totalHours"; /*)*/
public static final String PROJECT_HOURLY_RATE = /*$$(*/ "Project.hourlyRate"; /*)*/
public static final String PROJECT_ANALYTICAL = /*$$(*/ "Project.analyticalLines"; /*)*/
public static final String PROJECT_ANALYTICAL_AXIS = /*$$(*/ "Project.analyticalAxis"; /*)*/
public static final String PROJECT_ANALYTICAL_ACCOUNT = /*$$(*/ "Project.analyticalAccount"; /*)*/
public static final String PROJECT_TYPE = /*$$(*/ "Project.type"; /*)*/
public static final String PROJECT_TOTAL = /*$$(*/ "Project.total"; /*)*/
public static final String PROJECT_RESULT = /*$$(*/ "Project.result"; /*)*/
public static final String PROJECT_CHART_TITLE = /*$$(*/ "Project.turnoverAndCostPerMonth"; /*)*/
public static final String PROJECT_MANUAL_ELEMENT = /*$$(*/ "Project.manualElement"; /*)*/
public static final String PROJECT_MANUAL_ELEMENT_TITLE = /*$$(*/
"Project.manualElementTitle"; /*)*/
public static final String PROJECT_REPORT_TITLE_FOR_PLANIFICATION_AND_COST = /*$$(*/
"Project planification and costs"; /*)*/
public static final String PROJECT_REPORT_TITLE_FOR_FINANCIAL = /*$$(*/
"Projects financial report"; /*)*/
public static final String INVOICE_PURCHASE_INVOICE_NO_ANNEX = /*$$(*/
"Invoice.purchaseInvoiceNoAnnex"; /*)*/
public static final String INVOICE_PURCHASE_REFUND_NO_ANNEX = /*$$(*/
"Invoice.purchaseRefundNoAnnex"; /*)*/
public static final String INVOICE_INVOICE_NO_ANNEX = /*$$(*/ "Invoice.invoiceNoAnnex"; /*)*/
public static final String INVOICE_DRAFT_INVOICE_NO_ANNEX = /*$$(*/
"Invoice.draftInvoiceNoAnnex"; /*)*/
public static final String INVOICE_REFUND_NO_ANNEX = /*$$(*/ "Invoice.refundNoAnnex"; /*)*/
public static final String INVOICE_TIMESHEET_TITLE = /*$$(*/ "Invoice.timesheetTitle"; /*)*/
public static final String INVOICE_EXPENSE_TITLE = /*$$(*/ "Invoice.expenseTitle"; /*)*/
public static final String INVOICE_TIMESHEET_USER = /*$$(*/ "Invoice.timesheetUser"; /*)*/
public static final String INVOICE_TIMESHEET_ACTIVITY = /*$$(*/ "Invoice.timesheetActivity"; /*)*/
public static final String INVOICE_TIMESHEET_DURATION = /*$$(*/ "Invoice.timesheetDuration"; /*)*/
public static final String INVOICE_SUPPLIER_REFERENCE = /*$$(*/ "Invoice.supplierReference"; /*)*/
public static final String INVOICE_EXPENSE_TOTAL_AMOUNT = /*$$(*/
"Invoice.expenseTotalAmount"; /*)*/
public static final String INVOICE_EXPENSE_TAX_AMOUNT = /*$$(*/ "Invoice.expenseTaxAmount"; /*)*/
public static final String INVOICE_EXPENSE_PRODUCT = /*$$(*/ "Invoice.expenseProduct"; /*)*/
public static final String PROJECT_CONSUMED_TIME = /*$$(*/ "Project.consumedTime"; /*)*/
public static final String PROJECT_TOTAL_TIME_CHART = /*$$(*/ "Project.totalTimeChart"; /*)*/
public static final String PROJECT_TOTAL_COST_CHART = /*$$(*/ "Project.totalCostChart"; /*)*/
public static final String PROJECT_PLANNED_TIME = /*$$(*/ "Project.plannedTime"; /*)*/
public static final String PROJECT_SYNTHESIS = /*$$(*/ "Project.synthesis"; /*)*/
public static final String PROJECT_TIME = /*$$(*/ "Project.time"; /*)*/
public static final String PROJECT_REAL_PASSED = /*$$(*/ "Project.realPassed"; /*)*/
public static final String PROJECT_PLANNED_PASSED = /*$$(*/ "Project.plannedPast"; /*)*/
public static final String PROJECT_REMAIN_PLANNED = /*$$(*/ "Project.remainPlanned"; /*)*/
public static final String PROJECT_REMAIN_THEORY = /*$$(*/ "Project.remainInTheory"; /*)*/
public static final String PROJECT_CHART_MONTH_PASSED_TIME = /*$$(*/
"Project.chartTimePassedPerMonth"; /*)*/
public static final String PROJECT_CHART_MONTH_PASSED_COST = /*$$(*/
"Project.chartCostPassedPerMonth"; /*)*/
public static final String PROJECT_CHART_MONTH_REMAINING_TIME = /*$$(*/
"Project.chartTimeRemainingPerMonth"; /*)*/
public static final String PROJECT_CHART_MONTH_REMAINING_COST = /*$$(*/
"Project.chartCostRemainingPerMonth"; /*)*/
// InvoicingProject
public static final String INVOICING_PROJECT_ANNEX_DEADLINE = /*$$(*/
"InvoicingProjectAnnex.deadline"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_INVOICE_GENERATED = /*$$(*/
"InvoicingProjectAnnex.invoiceGenerated"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_BUSINESS_PROJECT = /*$$(*/
"InvoicingProjectAnnex.businessProject"; /*)*/
// Titles
public static final String INVOICING_PROJECT_ANNEX_TITLE = /*$$(*/
"InvoicingProjectAnnex.annex"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TITLE_SALES = /*$$(*/
"InvoicingProjectAnnex.sales"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TITLE_PURCHASES = /*$$(*/
"InvoicingProjectAnnex.purchases"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TITLE_TIME_SPENT = /*$$(*/
"InvoicingProjectAnnex.timeSpent"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TITLE_EXPENSES = /*$$(*/
"InvoicingProjectAnnex.expenses"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TITLE_PROJECTS = /*$$(*/
"InvoicingProjectAnnex.projects"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TITLE_TASKS = /*$$(*/
"InvoicingProjectAnnex.tasks"; /*)*/
// InvoicingProject - Sales
public static final String INVOICING_PROJECT_ANNEX_CODE = /*$$(*/
"InvoicingProjectAnnex.code"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_PRODUCT_NAME = /*$$(*/
"InvoicingProjectAnnex.productName"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_UNIT = /*$$(*/
"InvoicingProjectAnnex.unit"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_QTY = /*$$(*/
"InvoicingProjectAnnex.qty"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_UNIT_PRICE_WT = /*$$(*/
"InvoicingProjectAnnex.unitPriceWT"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_UNIT_PRICE_ATI = /*$$(*/
"InvoicingProjectAnnex.unitPriceATI"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TOTAL_ATI = /*$$(*/
"InvoicingProjectAnnex.totalATI"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TOTAL_WT = /*$$(*/
"InvoicingProjectAnnex.totalWT"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_ESTIMATED_SHIPPING_DATE = /*$$(*/
"InvoicingProjectAnnex.estimatedShippingDate"; /*)*/
// InvoicingProject - Purchases
public static final String INVOICING_PROJECT_ANNEX_PURCHASE_ORDER = /*$$(*/
"InvoicingProjectAnnex.purchaseOrder"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_SUPPLIER = /*$$(*/
"InvoicingProjectAnnex.supplier"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TO_INVOICE = /*$$(*/
"InvoicingProjectAnnex.toInvoice"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_INVOICED = /*$$(*/
"InvoicingProjectAnnex.invoiced"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_CURRENCY = /*$$(*/
"InvoicingProjectAnnex.currency"; /*)*/
// InvoicingProject - TimeSpent
public static final String INVOICING_PROJECT_ANNEX_USER = /*$$(*/
"InvoicingProjectAnnex.user"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TASK = /*$$(*/
"InvoicingProjectAnnex.task"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_DATE = /*$$(*/
"InvoicingProjectAnnex.date"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_ACTIVITY = /*$$(*/
"InvoicingProjectAnnex.activity"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_DURATION = /*$$(*/
"InvoicingProjectAnnex.duration"; /*)*/
// InvoicingProject - Expenses
public static final String INVOICING_PROJECT_ANNEX_PROJECT = /*$$(*/
"InvoicingProjectAnnex.project"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_EXPENSE_TYPE = /*$$(*/
"InvoicingProjectAnnex.expenseType"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_EXPENSE_DATE = /*$$(*/
"InvoicingProjectAnnex.expenseDate"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TOTAL_TAX = /*$$(*/
"InvoicingProjectAnnex.totalTax"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_COMMENTS = /*$$(*/
"InvoicingProjectAnnex.comments"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TOTAL_AMOUNT_WITH_TAX = /*$$(*/
"InvoicingProjectAnnex.totalAmountWT"; /*)*/
// InvoicingProject - Project
public static final String INVOICING_PROJECT_ANNEX_NAME = /*$$(*/
"InvoicingProjectAnnex.name"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_PARENT_PROJECT = /*$$(*/
"InvoicingProjectAnnex.parentProject"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_CUSTOMER = /*$$(*/
"InvoicingProjectAnnex.customer"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_ASSIGNED_TO = /*$$(*/
"InvoicingProjectAnnex.assignedTo"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_FROM_DATE = /*$$(*/
"InvoicingProjectAnnex.fromDate"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_TO_DATE = /*$$(*/
"InvoicingProjectAnnex.toDate"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_DUE_DATE = /*$$(*/
"InvoicingProjectAnnex.dueDate"; /*)*/
// InvoicingProject - Tasks
public static final String INVOICING_PROJECT_ANNEX_TASK_DATE = /*$$(*/
"InvoicingProjectAnnex.taskDate"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_STATUS = /*$$(*/
"InvoicingProjectAnnex.status"; /*)*/
public static final String INVOICING_PROJECT_ANNEX_PROGRESS = /*$$(*/
"InvoicingProjectAnnex.progress"; /*)*/
}

View File

@ -0,0 +1,56 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.base.service.CurrencyService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.base.service.tax.AccountManagementService;
import com.axelor.apps.contract.db.Contract;
import com.axelor.apps.contract.db.ContractLine;
import com.axelor.apps.contract.service.ContractLineServiceImpl;
import com.axelor.apps.project.db.Project;
import com.google.inject.Inject;
import java.util.List;
public class ContractLineServiceProjectImpl extends ContractLineServiceImpl {
@Inject
public ContractLineServiceProjectImpl(
AppBaseService appBaseService,
AccountManagementService accountManagementService,
CurrencyService currencyService) {
super(appBaseService, accountManagementService, currencyService);
}
@Override
public ContractLine createAnalyticDistributionWithTemplate(
ContractLine contractLine, Contract contract) {
contractLine = super.createAnalyticDistributionWithTemplate(contractLine, contract);
Project project = contract.getProject();
if (project != null) {
List<AnalyticMoveLine> analyticMoveLineList = contractLine.getAnalyticMoveLineList();
analyticMoveLineList.forEach(analyticMoveLine -> analyticMoveLine.setProject(project));
contractLine.setAnalyticMoveLineList(analyticMoveLineList);
}
return contractLine;
}
}

View File

@ -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.businessproject.service;
import com.axelor.apps.project.db.Project;
import java.util.List;
public interface ExpenseLineProjectService {
public void setProject(List<Long> expenseLineIds, Project project);
}

View File

@ -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.businessproject.service;
import com.axelor.apps.hr.db.ExpenseLine;
import com.axelor.apps.hr.db.repo.ExpenseLineRepository;
import com.axelor.apps.project.db.Project;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.util.List;
public class ExpenseLineProjectServiceImpl implements ExpenseLineProjectService {
@Inject private ExpenseLineRepository expenseLineRepo;
@Transactional
@Override
public void setProject(List<Long> expenseLineIds, Project project) {
if (expenseLineIds != null) {
List<ExpenseLine> expenseLineList =
expenseLineRepo.all().filter("self.id in ?1", expenseLineIds).fetch();
for (ExpenseLine line : expenseLineList) {
line.setProject(project);
expenseLineRepo.save(line);
}
}
}
}

View File

@ -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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.service.AccountManagementAccountService;
import com.axelor.apps.account.service.AccountingSituationService;
import com.axelor.apps.account.service.AnalyticMoveLineService;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.account.service.payment.PaymentModeService;
import com.axelor.apps.hr.db.ExpenseLine;
import com.axelor.apps.hr.db.repo.ExpenseRepository;
import com.axelor.apps.hr.service.config.AccountConfigHRService;
import com.axelor.apps.hr.service.config.HRConfigService;
import com.axelor.apps.hr.service.expense.ExpenseServiceImpl;
import com.axelor.apps.message.service.TemplateMessageService;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.List;
public class ExpenseServiceProjectImpl extends ExpenseServiceImpl {
@Inject
public ExpenseServiceProjectImpl(
MoveService moveService,
ExpenseRepository expenseRepository,
MoveLineService moveLineService,
AccountManagementAccountService accountManagementAccountService,
AppAccountService appAccountService,
AccountConfigHRService accountConfigService,
AccountingSituationService accountingSituationService,
AnalyticMoveLineService analyticMoveLineService,
HRConfigService hrConfigService,
TemplateMessageService templateMessageService,
PaymentModeService paymentModeService) {
super(
moveService,
expenseRepository,
moveLineService,
accountManagementAccountService,
appAccountService,
accountConfigService,
accountingSituationService,
analyticMoveLineService,
hrConfigService,
templateMessageService,
paymentModeService);
}
@Override
public List<InvoiceLine> createInvoiceLines(
Invoice invoice, List<ExpenseLine> expenseLineList, int priority) throws AxelorException {
List<InvoiceLine> invoiceLineList = new ArrayList<InvoiceLine>();
int count = 0;
for (ExpenseLine expenseLine : expenseLineList) {
invoiceLineList.addAll(this.createInvoiceLine(invoice, expenseLine, priority * 100 + count));
count++;
invoiceLineList.get(invoiceLineList.size() - 1).setProject(expenseLine.getProject());
}
return invoiceLineList;
}
}

View File

@ -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.businessproject.service;
import com.axelor.apps.project.db.Project;
import java.util.List;
public interface InvoiceLineProjectService {
public void setProject(List<Long> invoiceLineIds, Project project);
}

View File

@ -0,0 +1,84 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.repo.InvoiceLineRepository;
import com.axelor.apps.account.service.AccountManagementAccountService;
import com.axelor.apps.account.service.AnalyticMoveLineService;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.base.service.CurrencyService;
import com.axelor.apps.base.service.PriceListService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.purchase.service.PurchaseProductService;
import com.axelor.apps.supplychain.service.InvoiceLineSupplychainService;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.util.List;
public class InvoiceLineProjectServiceImpl extends InvoiceLineSupplychainService
implements InvoiceLineProjectService {
@Inject private InvoiceLineRepository invoiceLineRepo;
@Inject
public InvoiceLineProjectServiceImpl(
CurrencyService currencyService,
PriceListService priceListService,
AppAccountService appAccountService,
AnalyticMoveLineService analyticMoveLineService,
AccountManagementAccountService accountManagementAccountService,
PurchaseProductService purchaseProductService) {
super(
currencyService,
priceListService,
appAccountService,
analyticMoveLineService,
accountManagementAccountService,
purchaseProductService);
}
@Transactional
@Override
public void setProject(List<Long> invoiceLineIds, Project project) {
if (invoiceLineIds != null) {
List<InvoiceLine> invoiceLineList =
invoiceLineRepo.all().filter("self.id in ?1", invoiceLineIds).fetch();
for (InvoiceLine line : invoiceLineList) {
line.setProject(project);
invoiceLineRepo.save(line);
}
}
}
@Override
public List<AnalyticMoveLine> createAnalyticDistributionWithTemplate(InvoiceLine invoiceLine) {
List<AnalyticMoveLine> analyticMoveLineList =
super.createAnalyticDistributionWithTemplate(invoiceLine);
if (invoiceLine.getProject() != null && analyticMoveLineList != null) {
analyticMoveLineList.forEach(
analyticLine -> analyticLine.setProject(invoiceLine.getProject()));
}
return analyticMoveLineList;
}
}

View File

@ -0,0 +1,95 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoicePayment;
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
import com.axelor.apps.account.service.ReconcileService;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.account.service.payment.PaymentModeService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentToolService;
import com.axelor.apps.bankpayment.service.bankorder.BankOrderCreateService;
import com.axelor.apps.bankpayment.service.bankorder.BankOrderService;
import com.axelor.apps.bankpayment.service.invoice.payment.InvoicePaymentValidateServiceBankPayImpl;
import com.axelor.apps.businessproject.db.InvoicingProject;
import com.axelor.apps.businessproject.db.repo.InvoicingProjectRepository;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.exception.AxelorException;
import com.axelor.team.db.TeamTask;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.io.IOException;
import javax.xml.bind.JAXBException;
import javax.xml.datatype.DatatypeConfigurationException;
public class InvoicePaymentValidateProjectServiceImpl
extends InvoicePaymentValidateServiceBankPayImpl {
private InvoicingProjectRepository invoicingProjectRepo;
@Inject
public InvoicePaymentValidateProjectServiceImpl(
PaymentModeService paymentModeService,
MoveService moveService,
MoveLineService moveLineService,
AccountConfigService accountConfigService,
InvoicePaymentRepository invoicePaymentRepository,
ReconcileService reconcileService,
BankOrderCreateService bankOrderCreateService,
BankOrderService bankOrderService,
InvoicePaymentToolService invoicePaymentToolService,
InvoicingProjectRepository invoicingProjectRepo) {
super(
paymentModeService,
moveService,
moveLineService,
accountConfigService,
invoicePaymentRepository,
reconcileService,
bankOrderCreateService,
bankOrderService,
invoicePaymentToolService);
this.invoicingProjectRepo = invoicingProjectRepo;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void validate(InvoicePayment invoicePayment, boolean force)
throws AxelorException, JAXBException, IOException, DatatypeConfigurationException {
super.validate(invoicePayment, force);
Invoice invoice = invoicePayment.getInvoice();
InvoicingProject invoicingProject =
invoicingProjectRepo
.all()
.filter(
"self.invoice.id = ?1 AND self.project.invoicingSequenceSelect = ?2",
invoice.getId(),
ProjectRepository.INVOICING_SEQ_INVOICE_PRE_TASK)
.fetchOne();
if (invoicingProject != null) {
for (TeamTask teamTask : invoicingProject.getTeamTaskSet()) {
teamTask.setIsPaid(invoice.getHasPendingPayments());
}
}
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.businessproject.service;
import com.axelor.apps.ReportFactory;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.invoice.InvoiceLineService;
import com.axelor.apps.account.service.invoice.factory.CancelFactory;
import com.axelor.apps.account.service.invoice.factory.ValidateFactory;
import com.axelor.apps.account.service.invoice.factory.VentilateFactory;
import com.axelor.apps.base.service.PartnerService;
import com.axelor.apps.base.service.alarm.AlarmEngineService;
import com.axelor.apps.businessproject.report.IReport;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.supplychain.service.invoice.InvoiceServiceSupplychainImpl;
import com.axelor.auth.AuthUtils;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import java.util.Arrays;
import java.util.List;
public class InvoiceServiceProjectImpl extends InvoiceServiceSupplychainImpl {
@Inject
public InvoiceServiceProjectImpl(
ValidateFactory validateFactory,
VentilateFactory ventilateFactory,
CancelFactory cancelFactory,
AlarmEngineService<Invoice> alarmEngineService,
InvoiceRepository invoiceRepo,
AppAccountService appAccountService,
PartnerService partnerService,
InvoiceLineService invoiceLineService,
AccountConfigService accountConfigService) {
super(
validateFactory,
ventilateFactory,
cancelFactory,
alarmEngineService,
invoiceRepo,
appAccountService,
partnerService,
invoiceLineService,
accountConfigService);
}
public List<String> editInvoiceAnnex(Invoice invoice, String invoiceIds, boolean toAttach)
throws AxelorException {
if (invoice.getPrintingSettings() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_MISSING_FIELD,
String.format(
I18n.get(IExceptionMessage.INVOICE_MISSING_PRINTING_SETTINGS),
invoice.getInvoiceId()),
invoice);
}
if (!AuthUtils.getUser().getActiveCompany().getAccountConfig().getDisplayTimesheetOnPrinting()
&& !AuthUtils.getUser()
.getActiveCompany()
.getAccountConfig()
.getDisplayExpenseOnPrinting()) {
return null;
}
String language = ReportSettings.getPrintingLocale(invoice.getPartner());
String title = I18n.get("Invoice");
if (invoice.getInvoiceId() != null) {
title += invoice.getInvoiceId();
}
Integer invoicesCopy = invoice.getInvoicesCopySelect();
ReportSettings rS =
ReportFactory.createReport(
IReport.INVOICE_ANNEX, title + "-" + I18n.get("Annex") + "-${date}");
if (toAttach) {
rS.toAttach(invoice);
}
String fileLink =
rS.addParam("InvoiceId", invoiceIds)
.addParam("Locale", language)
.addParam("InvoicesCopy", invoicesCopy)
.addParam("HeaderHeight", invoice.getPrintingSettings().getPdfHeaderHeight())
.addParam("FooterHeight", invoice.getPrintingSettings().getPdfFooterHeight())
.generate()
.getFileLink();
List<String> res = Arrays.asList(title, fileLink);
return res;
}
}

View File

@ -0,0 +1,509 @@
/*
* 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.businessproject.service;
import com.axelor.apps.ReportFactory;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.invoice.generator.InvoiceGenerator;
import com.axelor.apps.account.service.invoice.generator.InvoiceLineGenerator;
import com.axelor.apps.account.service.invoice.print.InvoicePrintServiceImpl;
import com.axelor.apps.account.util.InvoiceLineComparator;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.repo.PriceListRepository;
import com.axelor.apps.base.service.PartnerPriceListService;
import com.axelor.apps.base.service.PartnerService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.businessproject.db.InvoicingProject;
import com.axelor.apps.businessproject.db.repo.InvoicingProjectRepository;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.report.IReport;
import com.axelor.apps.hr.db.ExpenseLine;
import com.axelor.apps.hr.db.TimesheetLine;
import com.axelor.apps.hr.db.repo.ExpenseLineRepository;
import com.axelor.apps.hr.db.repo.ExpenseRepository;
import com.axelor.apps.hr.db.repo.TimesheetLineRepository;
import com.axelor.apps.hr.service.expense.ExpenseService;
import com.axelor.apps.hr.service.timesheet.TimesheetService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.apps.project.service.ProjectServiceImpl;
import com.axelor.apps.purchase.db.PurchaseOrderLine;
import com.axelor.apps.purchase.db.repo.PurchaseOrderLineRepository;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderLineRepository;
import com.axelor.apps.sale.db.repo.SaleOrderRepository;
import com.axelor.apps.supplychain.service.invoice.generator.InvoiceLineGeneratorSupplyChain;
import com.axelor.apps.tool.file.PdfTool;
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.MetaFiles;
import com.axelor.meta.db.MetaFile;
import com.axelor.team.db.TeamTask;
import com.axelor.team.db.repo.TeamTaskRepository;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.io.File;
import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
public class InvoicingProjectService {
@Inject protected TimesheetService timesheetService;
@Inject protected ExpenseService expenseService;
@Inject protected PartnerService partnerService;
@Inject protected TeamTaskBusinessProjectService teamTaskBusinessProjectService;
@Inject protected InvoicingProjectRepository invoicingProjectRepo;
protected int MAX_LEVEL_OF_PROJECT = 10;
protected int sequence = 0;
protected static final String DATE_FORMAT_YYYYMMDDHHMM = "YYYYMMddHHmm";
@Transactional(rollbackOn = {Exception.class})
public Invoice generateInvoice(InvoicingProject invoicingProject) throws AxelorException {
Project project = invoicingProject.getProject();
Partner customer = project.getClientPartner();
Partner customerContact = project.getContactPartner();
if (customerContact == null && customer.getContactPartnerSet().size() == 1) {
customerContact = customer.getContactPartnerSet().iterator().next();
}
Company company = this.getRootCompany(project);
if (company == null) {
throw new AxelorException(
invoicingProject,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.INVOICING_PROJECT_PROJECT_COMPANY));
}
InvoiceGenerator invoiceGenerator =
new InvoiceGenerator(
InvoiceRepository.OPERATION_TYPE_CLIENT_SALE,
company,
customer.getPaymentCondition(),
customer.getInPaymentMode(),
partnerService.getInvoicingAddress(customer),
customer,
customerContact,
customer.getCurrency(),
Beans.get(PartnerPriceListService.class)
.getDefaultPriceList(customer, PriceListRepository.TYPE_SALE),
null,
null,
null,
null,
null) {
@Override
public Invoice generate() throws AxelorException {
Invoice invoice = super.createInvoiceHeader();
invoice.setProject(project);
invoice.setPriceList(project.getPriceList());
return invoice;
}
};
Invoice invoice = invoiceGenerator.generate();
AccountConfigService accountConfigService = Beans.get(AccountConfigService.class);
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
invoice.setDisplayTimesheetOnPrinting(accountConfig.getDisplayTimesheetOnPrinting());
invoice.setDisplayExpenseOnPrinting(accountConfig.getDisplayExpenseOnPrinting());
invoiceGenerator.populate(invoice, this.populate(invoice, invoicingProject));
Beans.get(InvoiceRepository.class).save(invoice);
invoicingProject.setInvoice(invoice);
invoicingProject.setStatusSelect(InvoicingProjectRepository.STATUS_GENERATED);
invoicingProjectRepo.save(invoicingProject);
return invoice;
}
public List<InvoiceLine> populate(Invoice invoice, InvoicingProject folder)
throws AxelorException {
List<SaleOrderLine> saleOrderLineList =
new ArrayList<SaleOrderLine>(folder.getSaleOrderLineSet());
List<PurchaseOrderLine> purchaseOrderLineList =
new ArrayList<PurchaseOrderLine>(folder.getPurchaseOrderLineSet());
List<TimesheetLine> timesheetLineList = new ArrayList<TimesheetLine>(folder.getLogTimesSet());
List<ExpenseLine> expenseLineList = new ArrayList<ExpenseLine>(folder.getExpenseLineSet());
List<TeamTask> teamTaskList = new ArrayList<TeamTask>(folder.getTeamTaskSet());
List<InvoiceLine> invoiceLineList = new ArrayList<InvoiceLine>();
invoiceLineList.addAll(
this.createSaleOrderInvoiceLines(
invoice, saleOrderLineList, folder.getSaleOrderLineSetPrioritySelect()));
invoiceLineList.addAll(
this.createPurchaseOrderInvoiceLines(
invoice, purchaseOrderLineList, folder.getPurchaseOrderLineSetPrioritySelect()));
invoiceLineList.addAll(
timesheetService.createInvoiceLines(
invoice, timesheetLineList, folder.getLogTimesSetPrioritySelect()));
invoiceLineList.addAll(
expenseService.createInvoiceLines(
invoice, expenseLineList, folder.getExpenseLineSetPrioritySelect()));
invoiceLineList.addAll(
teamTaskBusinessProjectService.createInvoiceLines(
invoice, teamTaskList, folder.getTeamTaskSetPrioritySelect()));
Collections.sort(invoiceLineList, new InvoiceLineComparator());
for (InvoiceLine invoiceLine : invoiceLineList) {
invoiceLine.setSequence(sequence);
sequence++;
}
return invoiceLineList;
}
public List<InvoiceLine> createSaleOrderInvoiceLines(
Invoice invoice, List<SaleOrderLine> saleOrderLineList, int priority) throws AxelorException {
List<InvoiceLine> invoiceLineList = new ArrayList<InvoiceLine>();
int count = 1;
for (SaleOrderLine saleOrderLine : saleOrderLineList) {
invoiceLineList.addAll(
this.createInvoiceLine(invoice, saleOrderLine, priority * 100 + count));
count++;
}
return invoiceLineList;
}
public List<InvoiceLine> createInvoiceLine(
Invoice invoice, SaleOrderLine saleOrderLine, int priority) throws AxelorException {
Product product = saleOrderLine.getProduct();
InvoiceLineGenerator invoiceLineGenerator =
new InvoiceLineGeneratorSupplyChain(
invoice,
product,
saleOrderLine.getProductName(),
saleOrderLine.getDescription(),
saleOrderLine.getQty(),
saleOrderLine.getUnit(),
priority,
false,
saleOrderLine,
null,
null,
false,
0) {
@Override
public List<InvoiceLine> creates() throws AxelorException {
InvoiceLine invoiceLine = this.createInvoiceLine();
invoiceLine.setProject(saleOrderLine.getProject());
List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>();
invoiceLines.add(invoiceLine);
return invoiceLines;
}
};
return invoiceLineGenerator.creates();
}
public List<InvoiceLine> createPurchaseOrderInvoiceLines(
Invoice invoice, List<PurchaseOrderLine> purchaseOrderLineList, int priority)
throws AxelorException {
List<InvoiceLine> invoiceLineList = new ArrayList<InvoiceLine>();
for (PurchaseOrderLine purchaseOrderLine : purchaseOrderLineList) {
invoiceLineList.addAll(
Beans.get(PurchaseOrderInvoiceProjectServiceImpl.class)
.createInvoiceLine(invoice, purchaseOrderLine));
}
return invoiceLineList;
}
public List<InvoiceLine> createInvoiceLine(
Invoice invoice, PurchaseOrderLine purchaseOrderLine, int priority) throws AxelorException {
Product product = purchaseOrderLine.getProduct();
InvoiceLineGeneratorSupplyChain invoiceLineGenerator =
new InvoiceLineGeneratorSupplyChain(
invoice,
product,
purchaseOrderLine.getProductName(),
purchaseOrderLine.getDescription(),
purchaseOrderLine.getQty(),
purchaseOrderLine.getUnit(),
priority,
false,
null,
purchaseOrderLine,
null,
false,
0) {
@Override
public List<InvoiceLine> creates() throws AxelorException {
InvoiceLine invoiceLine = this.createInvoiceLine();
List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>();
invoiceLines.add(invoiceLine);
return invoiceLines;
}
};
return invoiceLineGenerator.creates();
}
public void setLines(InvoicingProject invoicingProject, Project project, int counter) {
if (counter > ProjectServiceImpl.MAX_LEVEL_OF_PROJECT) {
return;
}
counter++;
this.fillLines(invoicingProject, project);
List<Project> projectChildrenList =
Beans.get(ProjectRepository.class).all().filter("self.parentProject = ?1", project).fetch();
for (Project projectChild : projectChildrenList) {
this.setLines(invoicingProject, projectChild, counter);
}
return;
}
public void fillLines(InvoicingProject invoicingProject, Project project) {
String commonQuery =
"self.project = :project AND self.toInvoice = true AND self.invoiced = false";
StringBuilder solQueryBuilder = new StringBuilder(commonQuery);
solQueryBuilder.append(
" AND (self.saleOrder.statusSelect = :statusConfirmed OR self.saleOrder.statusSelect = :statusCompleted)");
Map<String, Object> solQueryMap = new HashMap<>();
solQueryMap.put("project", project);
solQueryMap.put("statusConfirmed", SaleOrderRepository.STATUS_ORDER_CONFIRMED);
solQueryMap.put("statusCompleted", SaleOrderRepository.STATUS_ORDER_COMPLETED);
StringBuilder polQueryBuilder = new StringBuilder(commonQuery);
polQueryBuilder.append(
" AND (self.purchaseOrder.statusSelect = 3 OR self.purchaseOrder.statusSelect = 4)");
Map<String, Object> polQueryMap = new HashMap<>();
polQueryMap.put("project", project);
StringBuilder logTimesQueryBuilder = new StringBuilder(commonQuery);
Map<String, Object> logTimesQueryMap = new HashMap<>();
logTimesQueryMap.put("project", project);
StringBuilder expenseLineQueryBuilder = new StringBuilder(commonQuery);
expenseLineQueryBuilder.append(
" AND (self.expense.statusSelect = :statusValidated OR self.expense.statusSelect = :statusReimbursed)");
Map<String, Object> expenseLineQueryMap = new HashMap<>();
expenseLineQueryMap.put("project", project);
expenseLineQueryMap.put("statusValidated", ExpenseRepository.STATUS_VALIDATED);
expenseLineQueryMap.put("statusReimbursed", ExpenseRepository.STATUS_REIMBURSED);
StringBuilder taskQueryBuilder = new StringBuilder(commonQuery);
taskQueryBuilder.append(" AND self.invoicingType = :invoicingTypePackage");
Map<String, Object> taskQueryMap = new HashMap<>();
taskQueryMap.put("project", project);
taskQueryMap.put("invoicingTypePackage", TeamTaskRepository.INVOICING_TYPE_PACKAGE);
if (invoicingProject.getDeadlineDate() != null) {
solQueryBuilder.append(" AND self.saleOrder.creationDate < :deadlineDate");
solQueryMap.put("deadlineDate", invoicingProject.getDeadlineDate());
polQueryBuilder.append(" AND self.purchaseOrder.orderDate < :deadlineDate");
polQueryMap.put("deadlineDate", invoicingProject.getDeadlineDate());
logTimesQueryBuilder.append(" AND self.date < :deadlineDate");
logTimesQueryMap.put("deadlineDate", invoicingProject.getDeadlineDate());
expenseLineQueryBuilder.append(" AND self.expenseDate < :deadlineDate");
expenseLineQueryMap.put("deadlineDate", invoicingProject.getDeadlineDate());
taskQueryBuilder.append(" AND self.taskDeadline < :deadlineDate");
taskQueryMap.put("deadlineDate", invoicingProject.getDeadlineDate());
}
invoicingProject
.getSaleOrderLineSet()
.addAll(
Beans.get(SaleOrderLineRepository.class)
.all()
.filter(solQueryBuilder.toString())
.bind(solQueryMap)
.fetch());
invoicingProject
.getPurchaseOrderLineSet()
.addAll(
Beans.get(PurchaseOrderLineRepository.class)
.all()
.filter(polQueryBuilder.toString())
.bind(polQueryMap)
.fetch());
invoicingProject
.getLogTimesSet()
.addAll(
Beans.get(TimesheetLineRepository.class)
.all()
.filter(logTimesQueryBuilder.toString())
.bind(logTimesQueryMap)
.fetch());
invoicingProject
.getExpenseLineSet()
.addAll(
Beans.get(ExpenseLineRepository.class)
.all()
.filter(expenseLineQueryBuilder.toString())
.bind(expenseLineQueryMap)
.fetch());
invoicingProject
.getTeamTaskSet()
.addAll(
Beans.get(TeamTaskRepository.class)
.all()
.filter(taskQueryBuilder.toString())
.bind(taskQueryMap)
.fetch());
}
public void clearLines(InvoicingProject invoicingProject) {
invoicingProject.setSaleOrderLineSet(new HashSet<SaleOrderLine>());
invoicingProject.setPurchaseOrderLineSet(new HashSet<PurchaseOrderLine>());
invoicingProject.setLogTimesSet(new HashSet<TimesheetLine>());
invoicingProject.setExpenseLineSet(new HashSet<ExpenseLine>());
invoicingProject.setProjectSet(new HashSet<Project>());
invoicingProject.setTeamTaskSet(new HashSet<TeamTask>());
}
public Company getRootCompany(Project project) {
if (project.getParentProject() == null) {
return project.getCompany();
} else {
return getRootCompany(project.getParentProject());
}
}
public int countToInvoice(Project project) {
int toInvoiceCount = 0;
String query = "self.project = ?1";
if (project.getIsShowPhasesElements()) {
query = "(self.project = ?1 OR self.project.parentProject = ?1)";
}
query += " AND self.toInvoice = true AND self.invoiced = false";
toInvoiceCount += Beans.get(SaleOrderLineRepository.class).all().filter(query, project).count();
toInvoiceCount +=
Beans.get(PurchaseOrderLineRepository.class).all().filter(query, project).count();
toInvoiceCount += Beans.get(ExpenseLineRepository.class).all().filter(query, project).count();
toInvoiceCount += Beans.get(TimesheetLineRepository.class).all().filter(query, project).count();
toInvoiceCount += Beans.get(TeamTaskRepository.class).all().filter(query, project).count();
return toInvoiceCount;
}
public void generateAnnex(InvoicingProject invoicingProject) throws AxelorException, IOException {
String title =
I18n.get("InvoicingProjectAnnex")
+ "-"
+ Beans.get(AppBaseService.class)
.getTodayDateTime()
.format(DateTimeFormatter.ofPattern(DATE_FORMAT_YYYYMMDDHHMM));
ReportSettings reportSettings =
ReportFactory.createReport(IReport.INVOICING_PROJECT_ANNEX, title)
.addParam("InvProjectId", invoicingProject.getId())
.addParam("Locale", ReportSettings.getPrintingLocale(null));
if (invoicingProject.getAttachAnnexToInvoice()) {
List<File> fileList = new ArrayList<>();
MetaFiles metaFiles = Beans.get(MetaFiles.class);
fileList.add(
Beans.get(InvoicePrintServiceImpl.class)
.print(invoicingProject.getInvoice(), null, ReportSettings.FORMAT_PDF, null));
fileList.add(reportSettings.generate().getFile());
MetaFile metaFile = metaFiles.upload(PdfTool.mergePdf(fileList));
metaFile.setFileName(title + ".pdf");
metaFiles.attach(metaFile, null, invoicingProject);
return;
}
reportSettings.toAttach(invoicingProject).generate();
}
@Transactional(rollbackOn = {AxelorException.class, Exception.class})
public InvoicingProject generateInvoicingProject(Project project) {
if (project == null) {
return null;
}
InvoicingProject invoicingProject = new InvoicingProject();
invoicingProject.setProject(project);
clearLines(invoicingProject);
setLines(invoicingProject, project, 0);
if (invoicingProject.getSaleOrderLineSet().isEmpty()
&& invoicingProject.getPurchaseOrderLineSet().isEmpty()
&& invoicingProject.getLogTimesSet().isEmpty()
&& invoicingProject.getExpenseLineSet().isEmpty()
&& invoicingProject.getProjectSet().isEmpty()
&& invoicingProject.getTeamTaskSet().isEmpty()) {
return invoicingProject;
}
return invoicingProjectRepo.save(invoicingProject);
}
}

View File

@ -0,0 +1,47 @@
/*
* 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.businessproject.service;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.TaskTemplate;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.team.db.TeamTask;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
public interface ProductTaskTemplateService {
/**
* Convert task template list to team task list. This method is recursive.
*
* @param templates List of task template to use for convert.
* @param project Project to set for each team task.
* @param parent Parent task
* @param startDate The start date for tasks.
* @param qty The number copy of the task.
* @return List of team task convert.
*/
List<TeamTask> convert(
List<? extends TaskTemplate> templates,
Project project,
TeamTask parent,
LocalDateTime startDate,
BigDecimal qty,
SaleOrderLine saleOrderLine);
}

View File

@ -0,0 +1,95 @@
/*
* 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.businessproject.service;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.TaskTemplate;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.team.db.TeamTask;
import com.axelor.team.db.repo.TeamTaskRepository;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
public class ProductTaskTemplateServiceImpl implements ProductTaskTemplateService {
protected TeamTaskBusinessProjectService teamTaskBusinessProjectService;
protected TeamTaskRepository teamTaskRepository;
@Inject
public ProductTaskTemplateServiceImpl(
TeamTaskBusinessProjectService teamTaskBusinessProjectService,
TeamTaskRepository teamTaskRepository) {
this.teamTaskBusinessProjectService = teamTaskBusinessProjectService;
this.teamTaskRepository = teamTaskRepository;
}
@Override
@Transactional
public List<TeamTask> convert(
List<? extends TaskTemplate> templates,
Project project,
TeamTask parent,
LocalDateTime startDate,
BigDecimal qty,
SaleOrderLine saleOrderLine) {
List<TeamTask> tasks = new ArrayList<>();
Product product = saleOrderLine.getProduct();
for (TaskTemplate template : templates) {
BigDecimal qtyTmp = (template.getIsUniqueTaskForMultipleQuantity() ? BigDecimal.ONE : qty);
while (qtyTmp.signum() > 0) {
LocalDateTime dateWithDelay = startDate.plusHours(template.getDelayToStart().longValue());
TeamTask task =
teamTaskBusinessProjectService.create(template, project, dateWithDelay, qty);
task.setParentTask(parent);
task.setProduct(product);
task.setQuantity(!template.getIsUniqueTaskForMultipleQuantity() ? BigDecimal.ONE : qty);
task.setUnit(product.getUnit());
task.setUnitPrice(product.getSalePrice());
task.setExTaxTotal(task.getUnitPrice().multiply(task.getQuantity()));
if (saleOrderLine.getSaleOrder().getToInvoiceViaTask()) {
task.setToInvoice(true);
task.setInvoicingType(TeamTaskRepository.INVOICING_TYPE_PACKAGE);
}
tasks.add(teamTaskRepository.save(task));
// Only parent task can have multiple quantities
List<TeamTask> children =
convert(
template.getTaskTemplateList(),
project,
task,
dateWithDelay,
BigDecimal.ONE,
saleOrderLine);
tasks.addAll(children);
qtyTmp = qtyTmp.subtract(BigDecimal.ONE);
}
}
return tasks;
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.businessproject.service;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.service.ProjectService;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.exception.AxelorException;
public interface ProjectBusinessService extends ProjectService {
SaleOrder generateQuotation(Project project) throws AxelorException;
Project generateProject(SaleOrder saleOrder);
Project generatePhaseProject(SaleOrderLine saleOrderLine, Project parent);
}

View File

@ -0,0 +1,245 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.service.AccountingSituationService;
import com.axelor.apps.base.db.AppSupplychain;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.CompanyRepository;
import com.axelor.apps.base.db.repo.PriceListRepository;
import com.axelor.apps.base.service.AddressService;
import com.axelor.apps.base.service.DurationService;
import com.axelor.apps.base.service.PartnerPriceListService;
import com.axelor.apps.base.service.PartnerService;
import com.axelor.apps.businessproject.service.app.AppBusinessProjectService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.ProjectTemplate;
import com.axelor.apps.project.db.TaskTemplate;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.apps.project.service.ProjectServiceImpl;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderRepository;
import com.axelor.apps.sale.service.saleorder.SaleOrderCreateService;
import com.axelor.apps.supplychain.service.app.AppSupplychainService;
import com.axelor.auth.db.User;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import com.axelor.team.db.TeamTask;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
public class ProjectBusinessServiceImpl extends ProjectServiceImpl
implements ProjectBusinessService {
@Inject protected AppBusinessProjectService appBusinessProjectService;
@Inject protected ProjectRepository projectRepo;
@Inject protected PartnerService partnerService;
@Inject protected AddressService addressService;
@Inject
public ProjectBusinessServiceImpl(ProjectRepository projectRepository) {
super(projectRepository);
}
@Override
@Transactional(rollbackOn = {Exception.class})
public SaleOrder generateQuotation(Project project) throws AxelorException {
SaleOrder order = Beans.get(SaleOrderCreateService.class).createSaleOrder(project.getCompany());
Partner clientPartner = project.getClientPartner();
Partner contactPartner = project.getContactPartner();
if (contactPartner == null && clientPartner.getContactPartnerSet().size() == 1) {
contactPartner = clientPartner.getContactPartnerSet().iterator().next();
}
Company company = project.getCompany();
order.setProject(projectRepo.find(project.getId()));
order.setClientPartner(clientPartner);
order.setContactPartner(contactPartner);
order.setCompany(company);
order.setMainInvoicingAddress(partnerService.getInvoicingAddress(clientPartner));
order.setMainInvoicingAddressStr(
addressService.computeAddressStr(order.getMainInvoicingAddress()));
order.setDeliveryAddress(partnerService.getDeliveryAddress(clientPartner));
order.setDeliveryAddressStr(addressService.computeAddressStr(order.getDeliveryAddress()));
order.setIsNeedingConformityCertificate(clientPartner.getIsNeedingConformityCertificate());
order.setCompanyBankDetails(
Beans.get(AccountingSituationService.class)
.getCompanySalesBankDetails(company, clientPartner));
if (project.getCurrency() != null) {
order.setCurrency(project.getCurrency());
} else if (clientPartner.getCurrency() != null) {
order.setCurrency(clientPartner.getCurrency());
} else {
order.setCurrency(company.getCurrency());
}
if (project.getPriceList() != null) {
order.setPriceList(project.getPriceList());
} else {
order.setPriceList(
Beans.get(PartnerPriceListService.class)
.getDefaultPriceList(clientPartner, PriceListRepository.TYPE_SALE));
}
if (order.getPriceList() != null) {
order.setHideDiscount(order.getPriceList().getHideDiscount());
}
if (clientPartner.getPaymentCondition() != null) {
order.setPaymentCondition(clientPartner.getPaymentCondition());
} else {
if (company != null && company.getAccountConfig() != null) {
order.setPaymentCondition(company.getAccountConfig().getDefPaymentCondition());
}
}
if (clientPartner.getInPaymentMode() != null) {
order.setPaymentMode(clientPartner.getInPaymentMode());
} else {
if (company != null && company.getAccountConfig() != null) {
order.setPaymentMode(company.getAccountConfig().getInPaymentMode());
}
}
if (order.getDuration() != null && order.getCreationDate() != null) {
order.setEndOfValidityDate(
Beans.get(DurationService.class)
.computeDuration(order.getDuration(), order.getCreationDate()));
}
AppSupplychain appSupplychain = Beans.get(AppSupplychainService.class).getAppSupplychain();
if (appSupplychain != null) {
order.setShipmentMode(clientPartner.getShipmentMode());
order.setFreightCarrierMode(clientPartner.getFreightCarrierMode());
if (clientPartner.getFreightCarrierMode() != null) {
order.setCarrierPartner(clientPartner.getFreightCarrierMode().getCarrierPartner());
}
Boolean interco =
appSupplychain.getIntercoFromSale()
&& !order.getCreatedByInterco()
&& clientPartner != null
&& Beans.get(CompanyRepository.class)
.all()
.filter("self.partner = ?", clientPartner)
.fetchOne()
!= null;
order.setInterco(interco);
}
return Beans.get(SaleOrderRepository.class).save(order);
}
/**
* Generate project form SaleOrder and set bi-directional.
*
* @param saleOrder The order of origin.
* @return The project generated.
*/
@Override
public Project generateProject(SaleOrder saleOrder) {
Project project = projectRepo.findByName(saleOrder.getFullName() + "_project");
project =
project == null
? this.generateProject(
null,
saleOrder.getFullName() + "_project",
saleOrder.getSalemanUser(),
saleOrder.getCompany(),
saleOrder.getClientPartner())
: project;
saleOrder.setProject(project);
return project;
}
@Override
public Project generateProject(
Project parentProject,
String fullName,
User assignedTo,
Company company,
Partner clientPartner) {
Project project =
super.generateProject(parentProject, fullName, assignedTo, company, clientPartner);
if (assignedTo != null) {
project.addMembersUserSetItem(assignedTo);
}
project.setImputable(true);
if (parentProject != null && parentProject.getIsInvoicingTimesheet()) {
project.setIsInvoicingTimesheet(true);
}
return project;
}
@Override
public Project generatePhaseProject(SaleOrderLine saleOrderLine, Project parent) {
Project project =
generateProject(
parent,
saleOrderLine.getFullName(),
saleOrderLine.getSaleOrder().getSalemanUser(),
parent.getCompany(),
parent.getClientPartner());
project.setProjectTypeSelect(ProjectRepository.TYPE_PHASE);
saleOrderLine.setProject(project);
return project;
}
@Override
@Transactional
public Project createProjectFromTemplate(
ProjectTemplate projectTemplate, String projectCode, Partner clientPartner)
throws AxelorException {
Project project = super.createProjectFromTemplate(projectTemplate, projectCode, clientPartner);
if (projectTemplate.getIsBusinessProject()) {
project.setCurrency(clientPartner.getCurrency());
if (clientPartner.getPartnerAddressList() != null
&& !clientPartner.getPartnerAddressList().isEmpty()) {
project.setCustomerAddress(
clientPartner.getPartnerAddressList().iterator().next().getAddress());
}
if (clientPartner.getSalePartnerPriceList() != null
&& clientPartner.getSalePartnerPriceList().getPriceListSet() != null
&& !clientPartner.getSalePartnerPriceList().getPriceListSet().isEmpty()) {
project.setPriceList(
clientPartner.getSalePartnerPriceList().getPriceListSet().iterator().next());
}
project.setIsInvoicingExpenses(projectTemplate.getIsInvoicingExpenses());
project.setIsInvoicingPurchases(projectTemplate.getIsInvoicingPurchases());
project.setInvoicingComment(projectTemplate.getInvoicingComment());
project.setIsBusinessProject(projectTemplate.getIsBusinessProject());
}
return project;
}
@Override
public TeamTask createTask(TaskTemplate taskTemplate, Project project) {
TeamTask task = super.createTask(taskTemplate, project);
return task;
}
}

View File

@ -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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.base.service.DurationService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.contract.db.Contract;
import com.axelor.apps.contract.db.repo.ConsumptionLineRepository;
import com.axelor.apps.contract.db.repo.ContractLineRepository;
import com.axelor.apps.contract.db.repo.ContractRepository;
import com.axelor.apps.contract.service.ContractLineService;
import com.axelor.apps.contract.service.ContractServiceImpl;
import com.axelor.apps.contract.service.ContractVersionService;
import com.axelor.apps.project.db.Project;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
public class ProjectContractServiceImpl extends ContractServiceImpl {
@Inject
public ProjectContractServiceImpl(
AppBaseService appBaseService,
ContractVersionService versionService,
ContractLineService contractLineService,
DurationService durationService,
ContractLineRepository contractLineRepo,
ConsumptionLineRepository consumptionLineRepo,
ContractRepository contractRepository) {
super(
appBaseService,
versionService,
contractLineService,
durationService,
contractLineRepo,
consumptionLineRepo,
contractRepository);
}
@Override
public Invoice generateInvoice(Contract contract) throws AxelorException {
Invoice invoice = super.generateInvoice(contract);
Project project = contract.getProject();
if (project != null && project.getIsBusinessProject()) {
invoice.setProject(project);
}
return invoice;
}
}

View File

@ -0,0 +1,31 @@
/*
* 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.businessproject.service;
import com.axelor.apps.project.db.ProjectFolder;
import com.axelor.exception.AxelorException;
import java.io.IOException;
public interface ProjectFolderService {
String printProjectsPlanificationAndCost(ProjectFolder projectFolder)
throws IOException, AxelorException;
String printProjectFinancialReport(ProjectFolder projectFolder)
throws IOException, AxelorException;
}

View File

@ -0,0 +1,124 @@
/*
* 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.businessproject.service;
import com.axelor.apps.ReportFactory;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.businessproject.report.IReport;
import com.axelor.apps.businessproject.report.ITranslation;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.ProjectFolder;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.tool.ModelTool;
import com.axelor.apps.tool.ThrowConsumer;
import com.axelor.apps.tool.file.PdfTool;
import com.axelor.exception.AxelorException;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import java.io.File;
import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
public class ProjectFolderServiceImpl implements ProjectFolderService {
@Override
public String printProjectsPlanificationAndCost(ProjectFolder projectFolder)
throws IOException, AxelorException {
List<File> printedProjects = new ArrayList<>();
List<Long> ids = new ArrayList<Long>();
for (Project project : projectFolder.getProjectSet()) {
ids.add(project.getId());
}
ModelTool.apply(
Project.class,
ids,
new ThrowConsumer<Project>() {
@Override
public void accept(Project project) throws Exception {
String name = I18n.get(ITranslation.PROJECT_REPORT_TITLE_FOR_PLANIFICATION_AND_COST);
if (project.getCode() != null) {
name += " (" + project.getCode() + ")";
}
printedProjects.add(printCopiesToFile(project, name, IReport.PLANNIF_AND_COST));
}
});
String fileName =
getProjectFilesName(I18n.get(ITranslation.PROJECT_REPORT_TITLE_FOR_PLANIFICATION_AND_COST));
return PdfTool.mergePdfToFileLink(printedProjects, fileName);
}
@Override
public String printProjectFinancialReport(ProjectFolder projectFolder)
throws IOException, AxelorException {
List<File> printedProjects = new ArrayList<>();
List<Long> ids = new ArrayList<Long>();
for (Project project : projectFolder.getProjectSet()) {
ids.add(project.getId());
}
ModelTool.apply(
Project.class,
ids,
new ThrowConsumer<Project>() {
@Override
public void accept(Project project) throws Exception {
String name =
I18n.get(ITranslation.PROJECT_REPORT_TITLE_FOR_FINANCIAL) + " " + project.getCode();
printedProjects.add(printCopiesToFile(project, name, IReport.PROJECT));
}
});
String fileName =
getProjectFilesName(I18n.get(ITranslation.PROJECT_REPORT_TITLE_FOR_FINANCIAL));
return PdfTool.mergePdfToFileLink(printedProjects, fileName);
}
public File printCopiesToFile(Project project, String name, String reportDesignName)
throws AxelorException, IOException {
File file = print(project, name, reportDesignName);
return PdfTool.printCopiesToFile(file, 1);
}
public File print(Project project, String name, String reportDesignName) throws AxelorException {
ReportSettings reportSettings = prepareReportSettings(project, name, reportDesignName);
return reportSettings.generate().getFile();
}
private ReportSettings prepareReportSettings(
Project project, String name, String reportDesignName) {
ReportSettings reportSetting = ReportFactory.createReport(reportDesignName, name);
return reportSetting
.addParam("ProjectId", project.getId())
.addParam("Locale", ReportSettings.getPrintingLocale(null))
.addFormat(ReportSettings.FORMAT_PDF);
}
protected String getProjectFilesName(String fileName) {
return fileName
+ " - "
+ Beans.get(AppBaseService.class).getTodayDate().format(DateTimeFormatter.BASIC_ISO_DATE)
+ "."
+ ReportSettings.FORMAT_PDF;
}
}

View File

@ -0,0 +1,55 @@
/*
* 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.businessproject.service;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.purchase.db.PurchaseOrder;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.supplychain.service.PurchaseOrderLineServiceSupplychainImpl;
import com.axelor.apps.supplychain.service.PurchaseOrderServiceSupplychainImpl;
import com.axelor.apps.supplychain.service.SaleOrderPurchaseServiceImpl;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.util.List;
public class ProjectPurchaseServiceImpl extends SaleOrderPurchaseServiceImpl {
@Inject
public ProjectPurchaseServiceImpl(
PurchaseOrderServiceSupplychainImpl purchaseOrderServiceSupplychainImpl,
PurchaseOrderLineServiceSupplychainImpl purchaseOrderLineServiceSupplychainImpl) {
super(purchaseOrderServiceSupplychainImpl, purchaseOrderLineServiceSupplychainImpl);
}
@Override
@Transactional(rollbackOn = {Exception.class})
public PurchaseOrder createPurchaseOrder(
Partner supplierPartner, List<SaleOrderLine> saleOrderLineList, SaleOrder saleOrder)
throws AxelorException {
PurchaseOrder purchaseOrder =
super.createPurchaseOrder(supplierPartner, saleOrderLineList, saleOrder);
if (purchaseOrder != null && saleOrder != null) {
purchaseOrder.setProject(saleOrder.getProject());
}
return purchaseOrder;
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.purchase.db.PurchaseOrderLine;
import com.axelor.apps.purchase.db.repo.PurchaseOrderRepository;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderRepository;
import com.axelor.apps.stock.db.StockMoveLine;
import com.axelor.apps.stock.db.repo.StockMoveLineRepository;
import com.axelor.apps.supplychain.service.PurchaseOrderInvoiceService;
import com.axelor.apps.supplychain.service.SaleOrderInvoiceService;
import com.axelor.apps.supplychain.service.StockMoveInvoiceServiceImpl;
import com.axelor.apps.supplychain.service.StockMoveLineServiceSupplychain;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import java.math.BigDecimal;
import java.util.List;
public class ProjectStockMoveInvoiceServiceImpl extends StockMoveInvoiceServiceImpl {
@Inject
public ProjectStockMoveInvoiceServiceImpl(
SaleOrderInvoiceService saleOrderInvoiceService,
PurchaseOrderInvoiceService purchaseOrderInvoiceService,
StockMoveLineServiceSupplychain stockMoveLineServiceSupplychain,
InvoiceRepository invoiceRepository,
SaleOrderRepository saleOrderRepo,
PurchaseOrderRepository purchaseOrderRepo,
StockMoveLineRepository stockMoveLineRepository) {
super(
saleOrderInvoiceService,
purchaseOrderInvoiceService,
stockMoveLineServiceSupplychain,
invoiceRepository,
saleOrderRepo,
purchaseOrderRepo,
stockMoveLineRepository);
}
@Override
public List<InvoiceLine> createInvoiceLine(
Invoice invoice, StockMoveLine stockMoveLine, BigDecimal qty) throws AxelorException {
List<InvoiceLine> invoiceLines = super.createInvoiceLine(invoice, stockMoveLine, qty);
for (InvoiceLine invoiceLine : invoiceLines) {
SaleOrderLine saleOrderLine = invoiceLine.getSaleOrderLine();
if (saleOrderLine != null) {
invoiceLine.setProject(saleOrderLine.getProject());
}
PurchaseOrderLine purchaseOrderLine = invoiceLine.getPurchaseOrderLine();
if (purchaseOrderLine != null) {
invoiceLine.setProject(purchaseOrderLine.getProject());
}
}
return invoiceLines;
}
}

View File

@ -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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.service.invoice.generator.InvoiceLineGenerator;
import com.axelor.apps.base.db.PriceList;
import com.axelor.apps.base.db.PriceListLine;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.repo.AppBaseRepository;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.db.repo.PriceListLineRepository;
import com.axelor.apps.base.db.repo.PriceListRepository;
import com.axelor.apps.base.service.PartnerPriceListService;
import com.axelor.apps.base.service.PriceListService;
import com.axelor.apps.businessproject.service.app.AppBusinessProjectService;
import com.axelor.apps.purchase.db.PurchaseOrderLine;
import com.axelor.apps.purchase.service.PurchaseOrderLineServiceImpl;
import com.axelor.apps.supplychain.service.PurchaseOrderInvoiceServiceImpl;
import com.axelor.apps.supplychain.service.invoice.generator.InvoiceLineGeneratorSupplyChain;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class PurchaseOrderInvoiceProjectServiceImpl extends PurchaseOrderInvoiceServiceImpl {
@Inject private PriceListService priceListService;
@Inject private PurchaseOrderLineServiceImpl purchaseOrderLineServiceImpl;
@Inject protected AppBusinessProjectService appBusinessProjectService;
@Override
protected void processPurchaseOrderLine(
Invoice invoice, List<InvoiceLine> invoiceLineList, PurchaseOrderLine purchaseOrderLine)
throws AxelorException {
super.processPurchaseOrderLine(invoice, invoiceLineList, purchaseOrderLine);
invoiceLineList.get(invoiceLineList.size() - 1).setProject(purchaseOrderLine.getProject());
}
@Override
public List<InvoiceLine> createInvoiceLine(Invoice invoice, PurchaseOrderLine purchaseOrderLine)
throws AxelorException {
Product product = purchaseOrderLine.getProduct();
BigDecimal price = product.getCostPrice();
BigDecimal discountAmount = product.getCostPrice();
int discountTypeSelect = 1;
if (invoice.getPartner().getChargeBackPurchaseSelect()
== PartnerRepository.CHARGING_BACK_TYPE_PRICE_LIST) {
PriceList priceList =
Beans.get(PartnerPriceListService.class)
.getDefaultPriceList(invoice.getPartner(), PriceListRepository.TYPE_SALE);
if (priceList != null) {
PriceListLine priceListLine =
purchaseOrderLineServiceImpl.getPriceListLine(purchaseOrderLine, priceList, price);
if (priceListLine != null) {
discountTypeSelect = priceListLine.getTypeSelect();
}
if ((appBusinessProjectService.getAppBase().getComputeMethodDiscountSelect()
== AppBaseRepository.INCLUDE_DISCOUNT_REPLACE_ONLY
&& discountTypeSelect == PriceListLineRepository.TYPE_REPLACE)
|| appBusinessProjectService.getAppBase().getComputeMethodDiscountSelect()
== AppBaseRepository.INCLUDE_DISCOUNT) {
Map<String, Object> discounts =
priceListService.getDiscounts(priceList, priceListLine, price);
if (discounts != null) {
discountAmount = (BigDecimal) discounts.get("discountAmount");
price =
priceListService.computeDiscount(
price, (int) discounts.get("discountTypeSelect"), discountAmount);
}
} else {
Map<String, Object> discounts =
priceListService.getDiscounts(priceList, priceListLine, price);
if (discounts != null) {
discountAmount = (BigDecimal) discounts.get("discountAmount");
if (discounts.get("price") != null) {
price = (BigDecimal) discounts.get("price");
}
}
}
}
InvoiceLineGenerator invoiceLineGenerator =
new InvoiceLineGenerator(
invoice,
product,
product.getName(),
price,
price,
price,
purchaseOrderLine.getDescription(),
purchaseOrderLine.getQty(),
purchaseOrderLine.getUnit(),
null,
InvoiceLineGenerator.DEFAULT_SEQUENCE,
discountAmount,
discountTypeSelect,
null,
null,
false,
false,
0) {
@Override
public List<InvoiceLine> creates() throws AxelorException {
InvoiceLine invoiceLine = this.createInvoiceLine();
invoiceLine.setProject(purchaseOrderLine.getProject());
List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>();
invoiceLines.add(invoiceLine);
return invoiceLines;
}
};
return invoiceLineGenerator.creates();
} else if (invoice.getPartner().getChargeBackPurchaseSelect()
== PartnerRepository.CHARGING_BACK_TYPE_PERCENTAGE) {
price =
price
.multiply(
invoice
.getPartner()
.getChargeBackPurchase()
.divide(
new BigDecimal(100),
appBusinessProjectService.getNbDecimalDigitForUnitPrice(),
BigDecimal.ROUND_HALF_UP))
.setScale(
appBusinessProjectService.getNbDecimalDigitForUnitPrice(),
BigDecimal.ROUND_HALF_UP);
InvoiceLineGenerator invoiceLineGenerator =
new InvoiceLineGenerator(
invoice,
product,
product.getName(),
price,
price,
price,
purchaseOrderLine.getDescription(),
purchaseOrderLine.getQty(),
purchaseOrderLine.getUnit(),
null,
InvoiceLineGenerator.DEFAULT_SEQUENCE,
discountAmount,
discountTypeSelect,
null,
null,
false,
false,
0) {
@Override
public List<InvoiceLine> creates() throws AxelorException {
InvoiceLine invoiceLine = this.createInvoiceLine();
invoiceLine.setProject(purchaseOrderLine.getProject());
List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>();
invoiceLines.add(invoiceLine);
return invoiceLines;
}
};
return invoiceLineGenerator.creates();
} else {
InvoiceLineGeneratorSupplyChain invoiceLineGenerator =
new InvoiceLineGeneratorSupplyChain(
invoice,
product,
purchaseOrderLine.getProductName(),
purchaseOrderLine.getDescription(),
purchaseOrderLine.getQty(),
purchaseOrderLine.getUnit(),
purchaseOrderLine.getSequence(),
false,
null,
purchaseOrderLine,
null,
false,
0) {
@Override
public List<InvoiceLine> creates() throws AxelorException {
InvoiceLine invoiceLine = this.createInvoiceLine();
invoiceLine.setProject(purchaseOrderLine.getProject());
List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>();
invoiceLines.add(invoiceLine);
return invoiceLines;
}
};
return invoiceLineGenerator.creates();
}
}
}

View File

@ -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.businessproject.service;
import com.axelor.apps.project.db.Project;
import java.util.List;
public interface PurchaseOrderLineProjectService {
public void setProject(List<Long> purchaseOrderLineIds, Project project);
}

View File

@ -0,0 +1,64 @@
/*
* 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.businessproject.service;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.purchase.db.PurchaseOrder;
import com.axelor.apps.purchase.db.PurchaseOrderLine;
import com.axelor.apps.purchase.db.repo.PurchaseOrderLineRepository;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.supplychain.service.PurchaseOrderLineServiceSupplychainImpl;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.util.List;
public class PurchaseOrderLineServiceProjectImpl extends PurchaseOrderLineServiceSupplychainImpl
implements PurchaseOrderLineProjectService {
@Inject private PurchaseOrderLineRepository purchaseOrderLineRepo;
@Override
public PurchaseOrderLine createPurchaseOrderLine(
PurchaseOrder purchaseOrder, SaleOrderLine saleOrderLine) throws AxelorException {
PurchaseOrderLine line = super.createPurchaseOrderLine(purchaseOrder, saleOrderLine);
if (line != null && saleOrderLine != null) {
line.setProject(saleOrderLine.getProject());
}
return line;
}
@Transactional
@Override
public void setProject(List<Long> purchaseOrderLineIds, Project project) {
if (purchaseOrderLineIds != null) {
List<PurchaseOrderLine> purchaseOrderLineList =
purchaseOrderLineRepo.all().filter("self.id in ?1", purchaseOrderLineIds).fetch();
for (PurchaseOrderLine line : purchaseOrderLineList) {
line.setProject(project);
purchaseOrderLineRepo.save(line);
}
}
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.PaymentCondition;
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.base.db.Company;
import com.axelor.apps.base.db.Currency;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.PriceList;
import com.axelor.apps.businessproject.service.app.AppBusinessProjectService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderRepository;
import com.axelor.apps.sale.service.saleorder.SaleOrderLineService;
import com.axelor.apps.sale.service.saleorder.SaleOrderWorkflowServiceImpl;
import com.axelor.apps.stock.db.repo.StockMoveRepository;
import com.axelor.apps.supplychain.service.SaleOrderInvoiceServiceImpl;
import com.axelor.apps.supplychain.service.app.AppSupplychainService;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.List;
public class SaleOrderInvoiceProjectServiceImpl extends SaleOrderInvoiceServiceImpl {
private AppBusinessProjectService appBusinessProjectService;
@Inject
public SaleOrderInvoiceProjectServiceImpl(
AppSupplychainService appSupplychainService,
SaleOrderRepository saleOrderRepo,
InvoiceRepository invoiceRepo,
InvoiceService invoiceService,
AppBusinessProjectService appBusinessProjectService,
StockMoveRepository stockMoveRepository,
SaleOrderLineService saleOrderLineService,
SaleOrderWorkflowServiceImpl saleOrderWorkflowServiceImpl) {
super(
appSupplychainService,
saleOrderRepo,
invoiceRepo,
invoiceService,
saleOrderLineService,
stockMoveRepository,
saleOrderWorkflowServiceImpl);
this.appBusinessProjectService = appBusinessProjectService;
}
@Transactional(rollbackOn = {Exception.class})
public Invoice mergeInvoice(
List<Invoice> invoiceList,
Company company,
Currency currency,
Partner partner,
Partner contactPartner,
PriceList priceList,
PaymentMode paymentMode,
PaymentCondition paymentCondition,
SaleOrder saleOrder,
Project project)
throws AxelorException {
Invoice invoiceMerged =
super.mergeInvoice(
invoiceList,
company,
currency,
partner,
contactPartner,
priceList,
paymentMode,
paymentCondition,
saleOrder);
if (project != null
&& !appBusinessProjectService.getAppBusinessProject().getProjectInvoiceLines()) {
invoiceMerged.setProject(project);
for (InvoiceLine invoiceLine : invoiceMerged.getInvoiceLineList()) {
invoiceLine.setProject(project);
}
}
return invoiceMerged;
}
@Override
public List<InvoiceLine> createInvoiceLine(
Invoice invoice, SaleOrderLine saleOrderLine, BigDecimal qtyToInvoice)
throws AxelorException {
List<InvoiceLine> invoiceLines = super.createInvoiceLine(invoice, saleOrderLine, qtyToInvoice);
for (InvoiceLine invoiceLine : invoiceLines) {
if (saleOrderLine != null) {
invoiceLine.setProject(saleOrderLine.getProject());
}
}
return invoiceLines;
}
}

View File

@ -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.businessproject.service;
import com.axelor.apps.project.db.Project;
import java.util.List;
public interface SaleOrderLineProjectService {
public void setProject(List<Long> saleOrderLineIds, Project project);
}

View File

@ -0,0 +1,61 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderLineRepository;
import com.axelor.apps.supplychain.service.SaleOrderLineServiceSupplyChainImpl;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.util.List;
public class SaleOrderLineProjectServiceImpl extends SaleOrderLineServiceSupplyChainImpl
implements SaleOrderLineProjectService {
@Inject private SaleOrderLineRepository saleOrderLineRepo;
@Transactional
@Override
public void setProject(List<Long> saleOrderLineIds, Project project) {
if (saleOrderLineIds != null) {
List<SaleOrderLine> saleOrderLineList =
saleOrderLineRepo.all().filter("self.id in ?1", saleOrderLineIds).fetch();
for (SaleOrderLine line : saleOrderLineList) {
line.setProject(project);
saleOrderLineRepo.save(line);
}
}
}
@Override
public SaleOrderLine createAnalyticDistributionWithTemplate(SaleOrderLine saleOrderLine) {
SaleOrderLine soLine = super.createAnalyticDistributionWithTemplate(saleOrderLine);
List<AnalyticMoveLine> analyticMoveLineList = soLine.getAnalyticMoveLineList();
if (soLine.getProject() != null && analyticMoveLineList != null) {
analyticMoveLineList.forEach(analyticLine -> analyticLine.setProject(soLine.getProject()));
}
return soLine;
}
}

View File

@ -0,0 +1,57 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.base.db.AppBusinessProject;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.TaskTemplate;
import com.axelor.apps.project.service.TeamTaskProjectService;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.auth.db.User;
import com.axelor.exception.AxelorException;
import com.axelor.team.db.TeamTask;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
public interface TeamTaskBusinessProjectService extends TeamTaskProjectService {
TeamTask create(SaleOrderLine saleOrderLine, Project project, User assignedTo);
TeamTask create(TaskTemplate template, Project project, LocalDateTime date, BigDecimal qty);
TeamTask updateDiscount(TeamTask teamTask);
TeamTask compute(TeamTask teamTask);
List<InvoiceLine> createInvoiceLines(Invoice invoice, List<TeamTask> teamTaskList, int priority)
throws AxelorException;
List<InvoiceLine> createInvoiceLine(Invoice invoice, TeamTask teamTask, int priority)
throws AxelorException;
TeamTask computeDefaultInformation(TeamTask teamTask);
@Transactional(rollbackOn = {AxelorException.class, Exception.class})
TeamTask updateTask(TeamTask teamTask, AppBusinessProject appBusinessProject);
TeamTask resetTeamTaskValues(TeamTask teamTask);
}

View File

@ -0,0 +1,363 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.service.invoice.generator.InvoiceLineGenerator;
import com.axelor.apps.base.db.AppBusinessProject;
import com.axelor.apps.base.db.PriceList;
import com.axelor.apps.base.db.PriceListLine;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.repo.PriceListLineRepository;
import com.axelor.apps.base.db.repo.PriceListRepository;
import com.axelor.apps.base.service.PartnerPriceListService;
import com.axelor.apps.base.service.PriceListService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.TaskTemplate;
import com.axelor.apps.project.db.TeamTaskCategory;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.apps.project.service.TeamTaskProjectServiceImpl;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.service.app.AppSaleService;
import com.axelor.auth.db.User;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import com.axelor.team.db.TeamTask;
import com.axelor.team.db.repo.TeamTaskRepository;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class TeamTaskBusinessProjectServiceImpl extends TeamTaskProjectServiceImpl
implements TeamTaskBusinessProjectService {
private PriceListLineRepository priceListLineRepository;
private PriceListService priceListService;
@Inject
public TeamTaskBusinessProjectServiceImpl(
TeamTaskRepository teamTaskRepo,
PriceListLineRepository priceListLineRepository,
PriceListService priceListService) {
super(teamTaskRepo);
this.priceListLineRepository = priceListLineRepository;
this.priceListService = priceListService;
}
@Override
public TeamTask create(SaleOrderLine saleOrderLine, Project project, User assignedTo) {
TeamTask task = create(saleOrderLine.getFullName() + "_task", project, assignedTo);
task.setProduct(saleOrderLine.getProduct());
task.setUnit(saleOrderLine.getUnit());
task.setCurrency(project.getClientPartner().getCurrency());
if (project.getPriceList() != null) {
PriceListLine line =
priceListLineRepository.findByPriceListAndProduct(
project.getPriceList(), saleOrderLine.getProduct());
if (line != null) {
task.setUnitPrice(line.getAmount());
}
}
if (task.getUnitPrice() == null) {
task.setUnitPrice(saleOrderLine.getProduct().getSalePrice());
}
task.setQuantity(saleOrderLine.getQty());
task.setSaleOrderLine(saleOrderLine);
task.setToInvoice(
saleOrderLine.getSaleOrder() != null
? saleOrderLine.getSaleOrder().getToInvoiceViaTask()
: false);
return task;
}
@Override
public TeamTask create(
TaskTemplate template, Project project, LocalDateTime date, BigDecimal qty) {
TeamTask task = create(template.getName(), project, template.getAssignedTo());
task.setTaskDate(date.toLocalDate());
task.setTaskEndDate(date.plusHours(template.getDuration().longValue()).toLocalDate());
BigDecimal plannedHrs = template.getTotalPlannedHrs();
if (template.getIsUniqueTaskForMultipleQuantity() && qty.compareTo(BigDecimal.ONE) > 0) {
plannedHrs = plannedHrs.multiply(qty);
task.setName(task.getName() + " x" + qty.intValue());
}
task.setTotalPlannedHrs(plannedHrs);
return task;
}
@Override
public TeamTask updateDiscount(TeamTask teamTask) {
PriceList priceList = teamTask.getProject().getPriceList();
if (priceList == null) {
this.emptyDiscounts(teamTask);
return teamTask;
}
PriceListLine priceListLine =
this.getPriceListLine(teamTask, priceList, teamTask.getUnitPrice());
Map<String, Object> discounts =
priceListService.getReplacedPriceAndDiscounts(
priceList, priceListLine, teamTask.getUnitPrice());
if (discounts == null) {
this.emptyDiscounts(teamTask);
} else {
teamTask.setDiscountTypeSelect((Integer) discounts.get("discountTypeSelect"));
teamTask.setDiscountAmount((BigDecimal) discounts.get("discountAmount"));
if (discounts.get("price") != null) {
teamTask.setPriceDiscounted((BigDecimal) discounts.get("price"));
}
}
return teamTask;
}
private void emptyDiscounts(TeamTask teamTask) {
teamTask.setDiscountTypeSelect(PriceListLineRepository.AMOUNT_TYPE_NONE);
teamTask.setDiscountAmount(BigDecimal.ZERO);
teamTask.setPriceDiscounted(BigDecimal.ZERO);
}
private PriceListLine getPriceListLine(TeamTask teamTask, PriceList priceList, BigDecimal price) {
return priceListService.getPriceListLine(
teamTask.getProduct(), teamTask.getQuantity(), priceList, price);
}
@Override
public TeamTask compute(TeamTask teamTask) {
if (teamTask.getProduct() == null && teamTask.getProject() == null
|| teamTask.getUnitPrice() == null
|| teamTask.getQuantity() == null) {
return teamTask;
}
BigDecimal priceDiscounted = this.computeDiscount(teamTask);
BigDecimal exTaxTotal = this.computeAmount(teamTask.getQuantity(), priceDiscounted);
teamTask.setPriceDiscounted(priceDiscounted);
teamTask.setExTaxTotal(exTaxTotal);
return teamTask;
}
private BigDecimal computeDiscount(TeamTask teamTask) {
return priceListService.computeDiscount(
teamTask.getUnitPrice(), teamTask.getDiscountTypeSelect(), teamTask.getDiscountAmount());
}
private BigDecimal computeAmount(BigDecimal quantity, BigDecimal price) {
BigDecimal amount =
price
.multiply(quantity)
.setScale(AppSaleService.DEFAULT_NB_DECIMAL_DIGITS, RoundingMode.HALF_EVEN);
return amount;
}
@Override
public List<InvoiceLine> createInvoiceLines(
Invoice invoice, List<TeamTask> teamTaskList, int priority) throws AxelorException {
List<InvoiceLine> invoiceLineList = new ArrayList<>();
int count = 0;
for (TeamTask teamTask : teamTaskList) {
invoiceLineList.addAll(this.createInvoiceLine(invoice, teamTask, priority * 100 + count));
count++;
}
return invoiceLineList;
}
@Override
public List<InvoiceLine> createInvoiceLine(Invoice invoice, TeamTask teamTask, int priority)
throws AxelorException {
InvoiceLineGenerator invoiceLineGenerator =
new InvoiceLineGenerator(
invoice,
teamTask.getProduct(),
teamTask.getName(),
teamTask.getUnitPrice(),
BigDecimal.ZERO,
teamTask.getPriceDiscounted(),
teamTask.getDescription(),
teamTask.getQuantity(),
teamTask.getUnit(),
null,
priority,
teamTask.getDiscountAmount(),
teamTask.getDiscountTypeSelect(),
teamTask.getExTaxTotal(),
BigDecimal.ZERO,
false,
false,
0) {
@Override
public List<InvoiceLine> creates() throws AxelorException {
InvoiceLine invoiceLine = this.createInvoiceLine();
invoiceLine.setProject(teamTask.getProject());
invoiceLine.setSaleOrderLine(teamTask.getSaleOrderLine());
teamTask.setInvoiceLine(invoiceLine);
List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>();
invoiceLines.add(invoiceLine);
return invoiceLines;
}
};
return invoiceLineGenerator.creates();
}
@Override
protected void setModuleFields(TeamTask teamTask, LocalDate date, TeamTask newTeamTask) {
super.setModuleFields(teamTask, date, newTeamTask);
// Module 'business project' fields
// none
}
@Override
protected void updateModuleFields(TeamTask teamTask, TeamTask nextTeamTask) {
super.updateModuleFields(teamTask, nextTeamTask);
// Module 'business project' fields
nextTeamTask.setToInvoice(teamTask.getToInvoice());
nextTeamTask.setExTaxTotal(teamTask.getExTaxTotal());
nextTeamTask.setDiscountTypeSelect(teamTask.getDiscountTypeSelect());
nextTeamTask.setDiscountAmount(teamTask.getDiscountAmount());
nextTeamTask.setPriceDiscounted(teamTask.getPriceDiscounted());
nextTeamTask.setInvoicingType(teamTask.getInvoicingType());
nextTeamTask.setCustomerReferral(teamTask.getCustomerReferral());
}
@Transactional(rollbackOn = {AxelorException.class, Exception.class})
@Override
public TeamTask updateTask(TeamTask teamTask, AppBusinessProject appBusinessProject) {
teamTask = computeDefaultInformation(teamTask);
if (teamTask.getInvoicingType() == TeamTaskRepository.INVOICING_TYPE_PACKAGE) {
switch (teamTask.getProject().getInvoicingSequenceSelect()) {
case ProjectRepository.INVOICING_SEQ_INVOICE_PRE_TASK:
teamTask.setToInvoice(
appBusinessProject.getPreTaskStatusSet() != null
&& appBusinessProject.getPreTaskStatusSet().contains(teamTask.getStatus()));
break;
case ProjectRepository.INVOICING_SEQ_INVOICE_POST_TASK:
teamTask.setToInvoice(
appBusinessProject.getPostTaskStatusSet() != null
&& appBusinessProject.getPostTaskStatusSet().contains(teamTask.getStatus()));
break;
}
} else {
teamTask.setToInvoice(
teamTask.getInvoicingType() == TeamTaskRepository.INVOICING_TYPE_TIME_SPENT);
}
return teamTaskRepo.save(teamTask);
}
@Override
public TeamTask computeDefaultInformation(TeamTask teamTask) {
Product product = teamTask.getProduct();
if (product != null) {
teamTask.setInvoicingType(TeamTaskRepository.INVOICING_TYPE_PACKAGE);
if (teamTask.getUnitPrice() == null
|| teamTask.getUnitPrice().compareTo(BigDecimal.ZERO) == 0) {
teamTask.setUnitPrice(this.computeUnitPrice(teamTask));
}
} else {
TeamTaskCategory teamTaskCategory = teamTask.getTeamTaskCategory();
if (teamTaskCategory == null) {
return teamTask;
}
teamTask.setInvoicingType(teamTaskCategory.getDefaultInvoicingType());
teamTask.setProduct(teamTaskCategory.getDefaultProduct());
product = teamTask.getProduct();
if (product == null) {
return teamTask;
}
teamTask.setUnitPrice(this.computeUnitPrice(teamTask));
}
teamTask.setUnit(product.getSalesUnit() == null ? product.getUnit() : product.getSalesUnit());
teamTask.setCurrency(product.getSaleCurrency());
teamTask.setQuantity(teamTask.getBudgetedTime());
teamTask = this.updateDiscount(teamTask);
teamTask = this.compute(teamTask);
return teamTask;
}
private BigDecimal computeUnitPrice(TeamTask teamTask) {
Product product = teamTask.getProduct();
BigDecimal unitPrice = product.getSalePrice();
PriceList priceList =
Beans.get(PartnerPriceListService.class)
.getDefaultPriceList(
teamTask.getProject().getClientPartner(), PriceListRepository.TYPE_SALE);
if (priceList == null) {
return unitPrice;
}
PriceListLine priceListLine = this.getPriceListLine(teamTask, priceList, unitPrice);
Map<String, Object> discounts =
priceListService.getReplacedPriceAndDiscounts(priceList, priceListLine, unitPrice);
if (discounts == null) {
return unitPrice;
} else {
unitPrice =
priceListService.computeDiscount(
unitPrice,
(Integer) discounts.get("discountTypeSelect"),
(BigDecimal) discounts.get("discountAmount"));
}
return unitPrice;
}
@Override
public TeamTask resetTeamTaskValues(TeamTask teamTask) {
teamTask.setProduct(null);
teamTask.setInvoicingType(null);
teamTask.setToInvoice(null);
teamTask.setQuantity(null);
teamTask.setUnit(null);
teamTask.setUnitPrice(null);
teamTask.setCurrency(null);
teamTask.setExTaxTotal(null);
return teamTask;
}
}

View File

@ -0,0 +1,30 @@
/*
* 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.businessproject.service;
import com.axelor.apps.hr.db.TimesheetLine;
import com.axelor.exception.AxelorException;
import com.google.inject.persist.Transactional;
public interface TimesheetLineBusinessService {
TimesheetLine getDefaultToInvoice(TimesheetLine timesheetLine);
@Transactional(rollbackOn = {AxelorException.class, Exception.class})
public TimesheetLine updateTimesheetLines(TimesheetLine timesheetLine);
}

View File

@ -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.businessproject.service;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.hr.db.Timesheet;
import com.axelor.apps.hr.db.TimesheetLine;
import com.axelor.apps.hr.db.repo.TimesheetLineRepository;
import com.axelor.apps.hr.service.timesheet.TimesheetLineServiceImpl;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.auth.db.User;
import com.axelor.exception.AxelorException;
import com.axelor.team.db.TeamTask;
import com.axelor.team.db.repo.TeamTaskRepository;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
public class TimesheetLineProjectServiceImpl extends TimesheetLineServiceImpl
implements TimesheetLineBusinessService {
@Inject private ProjectRepository projectRepo;
@Inject private TeamTaskRepository teamTaskaRepo;
@Inject private TimesheetLineRepository timesheetLineRepo;
@Override
public TimesheetLine createTimesheetLine(
Project project,
Product product,
User user,
LocalDate date,
Timesheet timesheet,
BigDecimal hours,
String comments) {
TimesheetLine timesheetLine =
super.createTimesheetLine(project, product, user, date, timesheet, hours, comments);
if (project != null
&& (project.getIsInvoicingTimesheet()
|| (project.getParentProject() != null
&& project.getParentProject().getIsInvoicingTimesheet())))
timesheetLine.setToInvoice(true);
return timesheetLine;
}
@Override
public TimesheetLine getDefaultToInvoice(TimesheetLine timesheetLine) {
Project project =
timesheetLine.getProject() != null
? projectRepo.find(timesheetLine.getProject().getId())
: null;
TeamTask teamTask =
timesheetLine.getTeamTask() != null
? teamTaskaRepo.find(timesheetLine.getTeamTask().getId())
: null;
Boolean toInvoice = false;
if (teamTask != null) {
toInvoice = teamTask.getInvoicingType() == TeamTaskRepository.INVOICING_TYPE_TIME_SPENT;
} else if (project != null) {
toInvoice = project.getIsInvoicingTimesheet();
}
timesheetLine.setToInvoice(toInvoice);
return timesheetLine;
}
@Transactional(rollbackOn = {AxelorException.class, Exception.class})
@Override
public TimesheetLine updateTimesheetLines(TimesheetLine timesheetLine) {
timesheetLine = getDefaultToInvoice(timesheetLine);
return timesheetLineRepo.save(timesheetLine);
}
}

View File

@ -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.businessproject.service;
import com.axelor.apps.hr.db.TimesheetLine;
import com.axelor.exception.AxelorException;
import java.math.BigDecimal;
public interface TimesheetProjectService {
public BigDecimal computeDurationForCustomer(TimesheetLine timesheetLine) throws AxelorException;
}

View File

@ -0,0 +1,168 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.base.db.PriceList;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.service.PriceListService;
import com.axelor.apps.hr.db.TimesheetLine;
import com.axelor.apps.hr.service.app.AppHumanResourceService;
import com.axelor.apps.hr.service.config.HRConfigService;
import com.axelor.apps.hr.service.timesheet.TimesheetLineService;
import com.axelor.apps.hr.service.timesheet.TimesheetServiceImpl;
import com.axelor.apps.hr.service.user.UserHrService;
import com.axelor.apps.message.service.TemplateMessageService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectPlanningTimeRepository;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.auth.db.User;
import com.axelor.auth.db.repo.UserRepository;
import com.axelor.exception.AxelorException;
import com.axelor.team.db.repo.TeamTaskRepository;
import com.google.inject.Inject;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class TimesheetProjectServiceImpl extends TimesheetServiceImpl
implements TimesheetProjectService {
@Inject
public TimesheetProjectServiceImpl(
PriceListService priceListService,
AppHumanResourceService appHumanResourceService,
HRConfigService hrConfigService,
TemplateMessageService templateMessageService,
ProjectRepository projectRepo,
UserRepository userRepo,
UserHrService userHrService,
TimesheetLineService timesheetLineService,
ProjectPlanningTimeRepository projectPlanningTimeRepository,
TeamTaskRepository teamTaskRepository) {
super(
priceListService,
appHumanResourceService,
hrConfigService,
templateMessageService,
projectRepo,
userRepo,
userHrService,
timesheetLineService,
projectPlanningTimeRepository,
teamTaskRepository);
}
@Override
public List<InvoiceLine> createInvoiceLines(
Invoice invoice, List<TimesheetLine> timesheetLineList, int priority) throws AxelorException {
List<InvoiceLine> invoiceLineList = new ArrayList<InvoiceLine>();
int count = 0;
DateTimeFormatter ddmmFormat = DateTimeFormatter.ofPattern("dd/MM");
HashMap<String, Object[]> timeSheetInformationsMap = new HashMap<String, Object[]>();
// Check if a consolidation by product and user must be done
boolean consolidate = appHumanResourceService.getAppTimesheet().getConsolidateTSLine();
for (TimesheetLine timesheetLine : timesheetLineList) {
Object[] tabInformations = new Object[6];
tabInformations[0] = timesheetLine.getProduct();
tabInformations[1] = timesheetLine.getUser();
// Start date
tabInformations[2] = timesheetLine.getDate();
// End date, useful only for consolidation
tabInformations[3] = timesheetLine.getDate();
tabInformations[4] =
timesheetLine.getDurationForCustomer().compareTo(BigDecimal.ZERO) != 0
? this.computeDurationForCustomer(timesheetLine)
: timesheetLine.getHoursDuration();
tabInformations[5] = timesheetLine.getProject();
String key = null;
if (consolidate) {
key =
timesheetLine.getProduct().getId()
+ "|"
+ timesheetLine.getUser().getId()
+ "|"
+ timesheetLine.getProject().getId();
if (timeSheetInformationsMap.containsKey(key)) {
tabInformations = timeSheetInformationsMap.get(key);
// Update date
if (timesheetLine.getDate().compareTo((LocalDate) tabInformations[2]) < 0) {
// If date is lower than start date then replace start date by this one
tabInformations[2] = timesheetLine.getDate();
} else if (timesheetLine.getDate().compareTo((LocalDate) tabInformations[3]) > 0) {
// If date is upper than end date then replace end date by this one
tabInformations[3] = timesheetLine.getDate();
}
tabInformations[4] =
((BigDecimal) tabInformations[4])
.add(
timesheetLine.getDurationForCustomer().compareTo(BigDecimal.ZERO) != 0
? this.computeDurationForCustomer(timesheetLine)
: timesheetLine.getHoursDuration());
} else {
timeSheetInformationsMap.put(key, tabInformations);
}
} else {
key = String.valueOf(timesheetLine.getId());
timeSheetInformationsMap.put(key, tabInformations);
}
}
for (Object[] timesheetInformations : timeSheetInformationsMap.values()) {
String strDate = null;
Product product = (Product) timesheetInformations[0];
User user = (User) timesheetInformations[1];
LocalDate startDate = (LocalDate) timesheetInformations[2];
LocalDate endDate = (LocalDate) timesheetInformations[3];
BigDecimal hoursDuration = (BigDecimal) timesheetInformations[4];
Project project = (Project) timesheetInformations[5];
PriceList priceList = project.getPriceList();
if (consolidate) {
if (startDate != null && endDate != null) {
strDate = startDate.format(ddmmFormat) + " - " + endDate.format(ddmmFormat);
}
} else {
if (startDate != null) {
strDate = startDate.format(ddmmFormat);
}
}
invoiceLineList.addAll(
this.createInvoiceLine(
invoice, product, user, strDate, hoursDuration, priority * 100 + count, priceList));
invoiceLineList.get(invoiceLineList.size() - 1).setProject(project);
count++;
}
return invoiceLineList;
}
@Override
public BigDecimal computeDurationForCustomer(TimesheetLine timesheetLine) throws AxelorException {
return timesheetLineService.computeHoursDuration(
timesheetLine.getTimesheet(), timesheetLine.getDurationForCustomer(), true);
}
}

View File

@ -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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.businessproject.db.InvoicingProject;
import com.axelor.apps.businessproject.db.repo.InvoicingProjectRepository;
import com.axelor.apps.purchase.db.repo.PurchaseOrderRepository;
import com.axelor.apps.sale.db.repo.SaleOrderRepository;
import com.axelor.apps.supplychain.service.PurchaseOrderInvoiceService;
import com.axelor.apps.supplychain.service.SaleOrderInvoiceService;
import com.axelor.apps.supplychain.service.workflow.WorkflowCancelServiceSupplychainImpl;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
public class WorkflowCancelServiceProjectImpl extends WorkflowCancelServiceSupplychainImpl {
@Inject InvoicingProjectRepository invoicingProjectRepo;
@Inject
public WorkflowCancelServiceProjectImpl(
SaleOrderInvoiceService saleOrderInvoiceService,
PurchaseOrderInvoiceService purchaseOrderInvoiceService,
SaleOrderRepository saleOrderRepository,
PurchaseOrderRepository purchaseOrderRepository) {
super(
saleOrderInvoiceService,
purchaseOrderInvoiceService,
saleOrderRepository,
purchaseOrderRepository);
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void afterCancel(Invoice invoice) throws AxelorException {
super.afterCancel(invoice);
InvoicingProject invoicingProject =
invoicingProjectRepo.all().filter("self.invoice = ?", invoice.getId()).fetchOne();
if (invoicingProject != null) {
invoicingProject.setStatusSelect(InvoicingProjectRepository.STATUS_CANCELED);
invoicingProjectRepo.save(invoicingProject);
}
}
}

View File

@ -0,0 +1,51 @@
/*
* 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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.businessproject.db.InvoicingProject;
import com.axelor.apps.businessproject.db.repo.InvoicingProjectRepository;
import com.axelor.apps.supplychain.service.IntercoService;
import com.axelor.apps.supplychain.service.workflow.WorkflowValidationServiceSupplychainImpl;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
public class WorkflowValidationServiceProjectImpl extends WorkflowValidationServiceSupplychainImpl {
@Inject InvoicingProjectRepository invoicingProjectRepo;
@Inject
public WorkflowValidationServiceProjectImpl(IntercoService intercoService) {
super(intercoService);
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void afterValidation(Invoice invoice) throws AxelorException {
super.afterValidation(invoice);
InvoicingProject invoicingProject =
invoicingProjectRepo.all().filter("self.invoice = ?", invoice.getId()).fetchOne();
if (invoicingProject != null) {
invoicingProject.setStatusSelect(InvoicingProjectRepository.STATUS_VALIDATED);
invoicingProjectRepo.save(invoicingProject);
}
}
}

View File

@ -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.businessproject.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService;
import com.axelor.apps.businessproject.db.InvoicingProject;
import com.axelor.apps.businessproject.db.repo.InvoicingProjectRepository;
import com.axelor.apps.hr.db.ExpenseLine;
import com.axelor.apps.hr.db.TimesheetLine;
import com.axelor.apps.hr.db.repo.TimesheetLineRepository;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.purchase.db.PurchaseOrderLine;
import com.axelor.apps.purchase.db.repo.PurchaseOrderRepository;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderRepository;
import com.axelor.apps.supplychain.service.AccountingSituationSupplychainService;
import com.axelor.apps.supplychain.service.PurchaseOrderInvoiceService;
import com.axelor.apps.supplychain.service.SaleOrderInvoiceService;
import com.axelor.apps.supplychain.service.app.AppSupplychainService;
import com.axelor.apps.supplychain.service.workflow.WorkflowVentilationServiceSupplychainImpl;
import com.axelor.exception.AxelorException;
import com.axelor.team.db.TeamTask;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
public class WorkflowVentilationProjectServiceImpl
extends WorkflowVentilationServiceSupplychainImpl {
private InvoicingProjectRepository invoicingProjectRepo;
private TimesheetLineRepository timesheetLineRepo;
@Inject
public WorkflowVentilationProjectServiceImpl(
AccountConfigService accountConfigService,
InvoicePaymentRepository invoicePaymentRepo,
InvoicePaymentCreateService invoicePaymentCreateService,
SaleOrderInvoiceService saleOrderInvoiceService,
PurchaseOrderInvoiceService purchaseOrderInvoiceService,
SaleOrderRepository saleOrderRepository,
PurchaseOrderRepository purchaseOrderRepository,
AccountingSituationSupplychainService accountingSituationSupplychainService,
AppSupplychainService appSupplychainService,
InvoicingProjectRepository invoicingProjectRepo,
TimesheetLineRepository timesheetLineRepo) {
super(
accountConfigService,
invoicePaymentRepo,
invoicePaymentCreateService,
saleOrderInvoiceService,
purchaseOrderInvoiceService,
saleOrderRepository,
purchaseOrderRepository,
accountingSituationSupplychainService,
appSupplychainService);
this.invoicingProjectRepo = invoicingProjectRepo;
this.timesheetLineRepo = timesheetLineRepo;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void afterVentilation(Invoice invoice) throws AxelorException {
super.afterVentilation(invoice);
InvoicingProject invoicingProject =
invoicingProjectRepo.all().filter("self.invoice.id = ?", invoice.getId()).fetchOne();
if (invoicingProject != null) {
for (SaleOrderLine saleOrderLine : invoicingProject.getSaleOrderLineSet()) {
saleOrderLine.setInvoiced(true);
}
for (PurchaseOrderLine purchaseOrderLine : invoicingProject.getPurchaseOrderLineSet()) {
purchaseOrderLine.setInvoiced(true);
}
for (TimesheetLine timesheetLine : invoicingProject.getLogTimesSet()) {
timesheetLine.setInvoiced(true);
if (timesheetLine.getTeamTask() == null) {
continue;
}
timesheetLine
.getTeamTask()
.setInvoiced(this.checkInvoicedTimesheetLines(timesheetLine.getTeamTask()));
}
for (ExpenseLine expenseLine : invoicingProject.getExpenseLineSet()) {
expenseLine.setInvoiced(true);
}
for (TeamTask teamTask : invoicingProject.getTeamTaskSet()) {
teamTask.setInvoiced(true);
}
for (Project project : invoicingProject.getProjectSet()) {
project.setInvoiced(true);
}
invoicingProject.setStatusSelect(InvoicingProjectRepository.STATUS_VENTILATED);
invoicingProjectRepo.save(invoicingProject);
}
}
private boolean checkInvoicedTimesheetLines(TeamTask teamTask) {
long timesheetLineCnt =
timesheetLineRepo
.all()
.filter("self.teamTask.id = ?1 AND self.invoiced = ?2", teamTask.getId(), false)
.count();
return timesheetLineCnt == 0;
}
}

View File

@ -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.businessproject.service.app;
import com.axelor.apps.base.db.AppBusinessProject;
import com.axelor.apps.base.service.app.AppBaseService;
public interface AppBusinessProjectService extends AppBaseService {
public AppBusinessProject getAppBusinessProject();
}

View File

@ -0,0 +1,36 @@
/*
* 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.businessproject.service.app;
import com.axelor.apps.base.db.AppBusinessProject;
import com.axelor.apps.base.db.repo.AppBusinessProjectRepository;
import com.axelor.apps.base.service.app.AppBaseServiceImpl;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@Singleton
public class AppBusinessProjectServiceImpl extends AppBaseServiceImpl
implements AppBusinessProjectService {
@Inject private AppBusinessProjectRepository appBusinessProjectRepo;
@Override
public AppBusinessProject getAppBusinessProject() {
return appBusinessProjectRepo.all().fetchOne();
}
}

View File

@ -0,0 +1,113 @@
/*
* 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.businessproject.service.batch;
import com.axelor.apps.base.service.administration.AbstractBatch;
import com.axelor.apps.businessproject.db.InvoicingProject;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.InvoicingProjectService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.exception.db.repo.ExceptionOriginRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BatchInvoicingProjectService extends AbstractBatch {
protected ProjectRepository projectRepo;
protected InvoicingProjectService invoicingProjectService;
@Inject
public BatchInvoicingProjectService(
ProjectRepository projectRepo, InvoicingProjectService invoicingProjectService) {
this.projectRepo = projectRepo;
this.invoicingProjectService = invoicingProjectService;
}
@Override
protected void process() {
Map<String, Object> contextValues = null;
try {
contextValues = ProjectInvoicingAssistantBatchService.createJsonContext(batch);
} catch (Exception e) {
TraceBackService.trace(e);
}
List<Object> generatedInvoicingProjectList = new ArrayList<Object>();
List<Project> projectList =
projectRepo
.all()
.filter(
"self.toInvoice = ?1 AND self.statusSelect NOT IN (?2)",
true,
ProjectRepository.STATE_CANCELED,
ProjectRepository.STATE_FINISHED)
.fetch();
for (Project project : projectList) {
try {
InvoicingProject invoicingProject =
invoicingProjectService.generateInvoicingProject(project);
if (invoicingProject != null && invoicingProject.getId() != null) {
incrementDone();
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", invoicingProject.getId());
generatedInvoicingProjectList.add(map);
}
} catch (Exception e) {
incrementAnomaly();
TraceBackService.trace(
new Exception(
String.format(
I18n.get(IExceptionMessage.BATCH_INVOICING_PROJECT_1), project.getId()),
e),
ExceptionOriginRepository.INVOICE_ORIGIN,
batch.getId());
}
}
ProjectInvoicingAssistantBatchService.updateJsonObject(
batch, generatedInvoicingProjectList, "generatedInvoicingProjectSet", contextValues);
}
@Override
protected void stop() {
String comment =
String.format(
"\t* %s " + I18n.get(IExceptionMessage.BATCH_INVOICING_PROJECT_2) + "\n",
batch.getDone());
comment +=
String.format(
"\t" + I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.ALARM_ENGINE_BATCH_4),
batch.getAnomaly());
addComment(comment);
super.stop();
}
}

View File

@ -0,0 +1,181 @@
/*
* 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.businessproject.service.batch;
import com.axelor.apps.base.db.AppBusinessProject;
import com.axelor.apps.base.service.administration.AbstractBatch;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.TeamTaskBusinessProjectService;
import com.axelor.apps.businessproject.service.TimesheetLineBusinessService;
import com.axelor.apps.businessproject.service.app.AppBusinessProjectService;
import com.axelor.apps.hr.db.TimesheetLine;
import com.axelor.apps.hr.db.repo.TimesheetLineRepository;
import com.axelor.db.JPA;
import com.axelor.db.Query;
import com.axelor.exception.db.repo.ExceptionOriginRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.team.db.TeamTask;
import com.axelor.team.db.repo.TeamTaskRepository;
import com.google.common.base.Strings;
import com.google.inject.Inject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class BatchUpdateTaskService extends AbstractBatch {
protected AppBusinessProjectService appBusinessProjectService;
protected TeamTaskBusinessProjectService teamTaskBusinessProjectService;
protected TimesheetLineBusinessService timesheetLineBusinessService;
protected TeamTaskRepository teamTaskRepo;
protected TimesheetLineRepository timesheetLineRepo;
@Inject
public BatchUpdateTaskService(
TeamTaskBusinessProjectService teamTaskBusinessProjectService,
AppBusinessProjectService appBusinessProjectService,
TimesheetLineBusinessService timesheetLineBusinessService,
TeamTaskRepository teamTaskRepo,
TimesheetLineRepository timesheetLineRepo) {
this.teamTaskBusinessProjectService = teamTaskBusinessProjectService;
this.appBusinessProjectService = appBusinessProjectService;
this.timesheetLineBusinessService = timesheetLineBusinessService;
this.teamTaskRepo = teamTaskRepo;
this.timesheetLineRepo = timesheetLineRepo;
}
@Override
protected void process() {
AppBusinessProject appBusinessProject = appBusinessProjectService.getAppBusinessProject();
Map<String, Object> contextValues = null;
try {
contextValues = ProjectInvoicingAssistantBatchService.createJsonContext(batch);
} catch (Exception e) {
TraceBackService.trace(e);
}
List<Object> updatedTaskList = new ArrayList<Object>();
String filter =
!Strings.isNullOrEmpty(appBusinessProject.getExculdeTaskInvoicing())
? "self.id NOT IN (SELECT id FROM TeamTask WHERE "
+ appBusinessProject.getExculdeTaskInvoicing()
+ ")"
: "self.id NOT IN (0)";
Query<TeamTask> query =
teamTaskRepo
.all()
.filter(
filter
+ " AND self.project.toInvoice = :invoiceable "
+ "AND self.toInvoice = :toInvoice "
+ "AND self.isTaskRefused = :refused")
.bind("invoiceable", true)
.bind("toInvoice", false)
.bind("refused", false)
.order("id");
int offset = 0;
List<TeamTask> taskList;
while (!(taskList = query.fetch(FETCH_LIMIT, offset)).isEmpty()) {
findBatch();
offset += taskList.size();
for (TeamTask teamTask : taskList) {
try {
teamTask = teamTaskBusinessProjectService.updateTask(teamTask, appBusinessProject);
if (teamTask.getToInvoice()) {
offset--;
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", teamTask.getId());
updatedTaskList.add(map);
}
this.updateTimesheetLines(teamTask, contextValues);
} catch (Exception e) {
incrementAnomaly();
TraceBackService.trace(
new Exception(
String.format(
I18n.get(IExceptionMessage.BATCH_TASK_UPDATION_1), teamTask.getId()),
e),
ExceptionOriginRepository.INVOICE_ORIGIN,
batch.getId());
}
}
JPA.clear();
}
findBatch();
ProjectInvoicingAssistantBatchService.updateJsonObject(
batch, updatedTaskList, "updatedTaskSet", contextValues);
}
private void updateTimesheetLines(TeamTask teamTask, Map<String, Object> contextValues) {
if (!teamTask.getToInvoice()
|| teamTask.getInvoicingType() != TeamTaskRepository.INVOICING_TYPE_TIME_SPENT) {
return;
}
List<Object> updatedTimesheetLineList = new ArrayList<Object>();
List<TimesheetLine> timesheetLineList =
timesheetLineRepo
.all()
.filter("self.teamTask.id = :taskId AND self.toInvoice = :toInvoice")
.bind("taskId", teamTask.getId())
.bind("toInvoice", false)
.order("id")
.fetch();
for (TimesheetLine timesheetLine : timesheetLineList) {
try {
timesheetLine = timesheetLineBusinessService.updateTimesheetLines(timesheetLine);
if (timesheetLine.getToInvoice()) {
Map<String, Object> map = new HashMap<String, Object>();
map.put("id", timesheetLine.getId());
updatedTimesheetLineList.add(map);
}
} catch (Exception e) {
incrementAnomaly();
TraceBackService.trace(e, ExceptionOriginRepository.INVOICE_ORIGIN, batch.getId());
}
}
ProjectInvoicingAssistantBatchService.updateJsonObject(
batch, updatedTimesheetLineList, "updatedTimesheetLineSet", contextValues);
}
@Override
protected void stop() {
String comment = I18n.get(IExceptionMessage.BATCH_TASK_UPDATION_2);
comment +=
String.format(
"\t" + I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.ALARM_ENGINE_BATCH_4),
batch.getAnomaly());
super.stop();
addComment(comment);
}
}

View File

@ -0,0 +1,150 @@
/*
* 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.businessproject.service.batch;
import com.axelor.apps.base.db.Batch;
import com.axelor.apps.base.exceptions.IExceptionMessage;
import com.axelor.apps.base.service.administration.AbstractBatchService;
import com.axelor.apps.businessproject.db.ProjectInvoicingAssistantBatch;
import com.axelor.apps.businessproject.db.repo.ProjectInvoicingAssistantBatchRepository;
import com.axelor.db.EntityHelper;
import com.axelor.db.Model;
import com.axelor.db.mapper.Mapper;
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.rpc.Context;
import com.axelor.rpc.JsonContext;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
public class ProjectInvoicingAssistantBatchService extends AbstractBatchService {
@Override
protected Class<? extends Model> getModelClass() {
return ProjectInvoicingAssistantBatch.class;
}
@Override
public Batch run(Model model) throws AxelorException {
Batch batch;
ProjectInvoicingAssistantBatch projectInvoicingAssistantBatch =
(ProjectInvoicingAssistantBatch) model;
switch (projectInvoicingAssistantBatch.getActionSelect()) {
case ProjectInvoicingAssistantBatchRepository.ACTION_UPDATE_TASKS:
batch = updateTask(projectInvoicingAssistantBatch);
break;
case ProjectInvoicingAssistantBatchRepository.ACTION_GENERATE_INVOICING_PROJECT:
batch = generateInvoicingProject(projectInvoicingAssistantBatch);
break;
default:
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.BASE_BATCH_1),
projectInvoicingAssistantBatch.getActionSelect(),
projectInvoicingAssistantBatch.getCode());
}
return batch;
}
public Batch updateTask(ProjectInvoicingAssistantBatch projectInvoicingAssistantBatch) {
return Beans.get(BatchUpdateTaskService.class).run(projectInvoicingAssistantBatch);
}
public Batch generateInvoicingProject(
ProjectInvoicingAssistantBatch projectInvoicingAssistantBatch) {
return Beans.get(BatchInvoicingProjectService.class).run(projectInvoicingAssistantBatch);
}
@SuppressWarnings("unchecked")
public static Map<String, Object> createJsonContext(Batch batch) throws ClassNotFoundException {
Context context = new Context(batch.getClass());
Class<? extends Model> klass =
(Class<? extends Model>) Class.forName(batch.getClass().getName());
JsonContext jsonContext =
new JsonContext(context, Mapper.of(klass).getProperty("attrs"), batch.getAttrs());
Map<String, Object> _map = new HashMap<String, Object>();
_map.put("context", context);
_map.put("jsonContext", jsonContext);
return _map;
}
@SuppressWarnings("unchecked")
public static void updateJsonObject(
Batch batch, List<Object> recordList, String field, Map<String, Object> contextValues) {
JsonContext jsonContext = (JsonContext) contextValues.get("jsonContext");
List<Object> dataList = recordList;
if (jsonContext.containsKey(field)) {
dataList =
((List<Object>) jsonContext.get(field))
.stream()
.map(
obj -> {
if (Mapper.toMap(EntityHelper.getEntity(obj)).get("id") != null) {
Map<String, Object> idMap = new HashMap<String, Object>();
idMap.put("id", Mapper.toMap(EntityHelper.getEntity(obj)).get("id"));
return idMap;
}
return obj;
})
.collect(Collectors.toList());
dataList.addAll(recordList);
}
jsonContext.put(field, dataList);
Context context = (Context) contextValues.get("context");
batch.setAttrs(context.get("attrs").toString());
}
@SuppressWarnings("unchecked")
public String getShowRecordIds(Batch batch, String field) throws ClassNotFoundException {
Context context = new Context(batch.getClass());
Class<? extends Model> klass =
(Class<? extends Model>) Class.forName(batch.getClass().getName());
JsonContext jsonContext =
new JsonContext(context, Mapper.of(klass).getProperty("attrs"), batch.getAttrs());
List<Map<String, Object>> recordList = (List<Map<String, Object>>) jsonContext.get(field);
String ids =
!CollectionUtils.isEmpty(recordList)
? recordList
.stream()
.map(_map -> _map.get("id").toString())
.collect(Collectors.joining(","))
: null;
return ids;
}
}

View File

@ -0,0 +1,96 @@
/*
* 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.businessproject.service.projectgenerator;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.projectgenerator.factory.ProjectGeneratorFactoryAlone;
import com.axelor.apps.businessproject.service.projectgenerator.factory.ProjectGeneratorFactoryPhase;
import com.axelor.apps.businessproject.service.projectgenerator.factory.ProjectGeneratorFactoryTask;
import com.axelor.apps.businessproject.service.projectgenerator.factory.ProjectGeneratorFactoryTaskTemplate;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.ProjectGeneratorType;
import com.axelor.apps.sale.db.SaleOrder;
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.schema.actions.ActionView.ActionViewBuilder;
import java.time.LocalDateTime;
public interface ProjectGeneratorFactory {
/**
* Create and fill project from sale order.
*
* @param saleOrder Use for generate project.
* @param localDateTime The date to use for create project's elements.
* @return The project generate.
* @throws AxelorException If a error occur on creating or filling.
*/
default Project generate(SaleOrder saleOrder, LocalDateTime localDateTime)
throws AxelorException {
Project project = create(saleOrder);
fill(project, saleOrder, localDateTime);
return project;
}
/**
* Return the factory associate to generator type.
*
* @param type The type of factory.
* @return The factory associate to type.
* @throws AxelorException If none factory is found for type.
*/
static ProjectGeneratorFactory getFactory(ProjectGeneratorType type) throws AxelorException {
switch (type) {
case PROJECT_ALONE:
return Beans.get(ProjectGeneratorFactoryAlone.class);
case TASK_BY_LINE:
return Beans.get(ProjectGeneratorFactoryTask.class);
case PHASE_BY_LINE:
return Beans.get(ProjectGeneratorFactoryPhase.class);
case TASK_TEMPLATE:
return Beans.get(ProjectGeneratorFactoryTaskTemplate.class);
default:
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.FACTORY_NO_FOUND));
}
}
/**
* Create the project from sale order.
*
* @param saleOrder Sale order to be use for create project.
* @return The new project create.
* @throws AxelorException If a error occur on creating.
*/
Project create(SaleOrder saleOrder) throws AxelorException;
/**
* Fill the project with elements from sale order.
*
* @param project Project to be fill.
* @param saleOrder Sale order to be use for fill project.
* @param localDateTime The date to use for create project's elements.
* @return The project fill with elements from sale order.
* @throws AxelorException If a error occur on filling.
*/
ActionViewBuilder fill(Project project, SaleOrder saleOrder, LocalDateTime localDateTime)
throws AxelorException;
}

View File

@ -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.businessproject.service.projectgenerator.factory;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.ProjectBusinessService;
import com.axelor.apps.businessproject.service.projectgenerator.ProjectGeneratorFactory;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.time.LocalDateTime;
public class ProjectGeneratorFactoryAlone implements ProjectGeneratorFactory {
private ProjectBusinessService projectBusinessService;
private ProjectRepository projectRepository;
@Inject
public ProjectGeneratorFactoryAlone(
ProjectBusinessService projectBusinessService, ProjectRepository projectRepository) {
this.projectBusinessService = projectBusinessService;
this.projectRepository = projectRepository;
}
@Override
@Transactional
public Project create(SaleOrder saleOrder) {
Project project = projectBusinessService.generateProject(saleOrder);
project.setIsProject(false);
project.setIsBusinessProject(true);
return projectRepository.save(project);
}
@Override
public ActionViewBuilder fill(Project project, SaleOrder saleOrder, LocalDateTime localDateTime)
throws AxelorException {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.FACTORY_FILL_WITH_PROJECT_ALONE));
}
}

View File

@ -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.businessproject.service.projectgenerator.factory;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.repo.ProductRepository;
import com.axelor.apps.businessproject.service.ProductTaskTemplateService;
import com.axelor.apps.businessproject.service.ProjectBusinessService;
import com.axelor.apps.businessproject.service.projectgenerator.ProjectGeneratorFactory;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderLineRepository;
import com.axelor.apps.tool.StringTool;
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.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
public class ProjectGeneratorFactoryPhase implements ProjectGeneratorFactory {
private ProjectBusinessService projectBusinessService;
private ProjectRepository projectRepository;
private SaleOrderLineRepository saleOrderLineRepository;
private ProductTaskTemplateService productTaskTemplateService;
@Inject
public ProjectGeneratorFactoryPhase(
ProjectBusinessService projectBusinessService,
ProjectRepository projectRepository,
SaleOrderLineRepository saleOrderLineRepository,
ProductTaskTemplateService productTaskTemplateService) {
this.projectBusinessService = projectBusinessService;
this.projectRepository = projectRepository;
this.saleOrderLineRepository = saleOrderLineRepository;
this.productTaskTemplateService = productTaskTemplateService;
}
@Override
public Project create(SaleOrder saleOrder) {
Project project = projectBusinessService.generateProject(saleOrder);
project.setIsProject(true);
project.setIsBusinessProject(true);
return project;
}
@Override
@Transactional
public ActionViewBuilder fill(Project project, SaleOrder saleOrder, LocalDateTime startDate) {
List<Project> projects = new ArrayList<>();
projectRepository.save(project);
for (SaleOrderLine saleOrderLine : saleOrder.getSaleOrderLineList()) {
Product product = saleOrderLine.getProduct();
if (ProductRepository.PRODUCT_TYPE_SERVICE.equals(product.getProductTypeSelect())
&& saleOrderLine.getSaleSupplySelect() == SaleOrderLineRepository.SALE_SUPPLY_PRODUCE) {
Project phase = projectBusinessService.generatePhaseProject(saleOrderLine, project);
phase.setFromDate(startDate);
saleOrderLineRepository.save(saleOrderLine);
projects.add(phase);
if (!CollectionUtils.isEmpty(product.getTaskTemplateSet())) {
productTaskTemplateService.convert(
product
.getTaskTemplateSet()
.stream()
.filter(template -> Objects.isNull(template.getParentTaskTemplate()))
.collect(Collectors.toList()),
phase,
null,
startDate,
saleOrderLine.getQty(),
saleOrderLine);
}
}
}
return ActionView.define(String.format("Project%s generated", (projects.size() > 1 ? "s" : "")))
.model(Project.class.getName())
.add("grid", "project-grid")
.add("form", "project-form")
.domain(String.format("self.id in (%s)", StringTool.getIdListString(projects)));
}
}

View File

@ -0,0 +1,122 @@
/*
* 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.businessproject.service.projectgenerator.factory;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.repo.ProductRepository;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.ProjectBusinessService;
import com.axelor.apps.businessproject.service.TeamTaskBusinessProjectService;
import com.axelor.apps.businessproject.service.projectgenerator.ProjectGeneratorFactory;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderLineRepository;
import com.axelor.apps.tool.StringTool;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.meta.schema.actions.ActionView;
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
import com.axelor.team.db.TeamTask;
import com.axelor.team.db.repo.TeamTaskRepository;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
public class ProjectGeneratorFactoryTask implements ProjectGeneratorFactory {
private ProjectBusinessService projectBusinessService;
private ProjectRepository projectRepository;
private TeamTaskBusinessProjectService teamTaskBusinessProjectService;
private TeamTaskRepository teamTaskRepository;
@Inject
public ProjectGeneratorFactoryTask(
ProjectBusinessService projectBusinessService,
ProjectRepository projectRepository,
TeamTaskBusinessProjectService teamTaskBusinessProjectService,
TeamTaskRepository teamTaskRepository) {
this.projectBusinessService = projectBusinessService;
this.projectRepository = projectRepository;
this.teamTaskBusinessProjectService = teamTaskBusinessProjectService;
this.teamTaskRepository = teamTaskRepository;
}
@Override
public Project create(SaleOrder saleOrder) {
Project project = projectBusinessService.generateProject(saleOrder);
project.setIsProject(true);
project.setIsBusinessProject(true);
return project;
}
@Override
@Transactional(rollbackOn = {Exception.class, AxelorException.class})
public ActionViewBuilder fill(Project project, SaleOrder saleOrder, LocalDateTime startDate)
throws AxelorException {
List<TeamTask> tasks = new ArrayList<>();
projectRepository.save(project);
for (SaleOrderLine saleOrderLine : saleOrder.getSaleOrderLineList()) {
Product product = saleOrderLine.getProduct();
boolean isTaskGenerated =
teamTaskRepository
.all()
.filter("self.saleOrderLine = ? AND self.project = ?", saleOrderLine, project)
.fetch()
.size()
> 0;
if (ProductRepository.PRODUCT_TYPE_SERVICE.equals(product.getProductTypeSelect())
&& saleOrderLine.getSaleSupplySelect() == SaleOrderLineRepository.SALE_SUPPLY_PRODUCE
&& !(isTaskGenerated)) {
TeamTask task =
teamTaskBusinessProjectService.create(saleOrderLine, project, project.getAssignedTo());
if (saleOrder.getToInvoiceViaTask()) {
task.setInvoicingType(TeamTaskRepository.INVOICING_TYPE_PACKAGE);
}
task.setTaskDate(startDate.toLocalDate());
task.setUnitPrice(product.getSalePrice());
task.setExTaxTotal(saleOrderLine.getExTaxTotal());
if (project.getIsInvoicingTimesheet()) {
task.setToInvoice(true);
} else {
task.setToInvoice(false);
}
teamTaskRepository.save(task);
tasks.add(task);
}
}
if (tasks == null || tasks.isEmpty()) {
throw new AxelorException(
TraceBackRepository.CATEGORY_NO_VALUE,
I18n.get(IExceptionMessage.SALE_ORDER_GENERATE_FILL_PROJECT_ERROR_1));
}
return ActionView.define(String.format("Task%s generated", (tasks.size() > 1 ? "s" : "")))
.model(TeamTask.class.getName())
.add("grid", "team-task-grid")
.add("form", "team-task-form")
.domain(String.format("self.id in (%s)", StringTool.getIdListString(tasks)));
}
}

View File

@ -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.businessproject.service.projectgenerator.factory;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.db.repo.ProductRepository;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.ProductTaskTemplateService;
import com.axelor.apps.businessproject.service.ProjectBusinessService;
import com.axelor.apps.businessproject.service.TeamTaskBusinessProjectService;
import com.axelor.apps.businessproject.service.projectgenerator.ProjectGeneratorFactory;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderLineRepository;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.meta.schema.actions.ActionView;
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
import com.axelor.team.db.TeamTask;
import com.axelor.team.db.repo.TeamTaskRepository;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
public class ProjectGeneratorFactoryTaskTemplate implements ProjectGeneratorFactory {
private ProjectBusinessService projectBusinessService;
private ProjectRepository projectRepository;
private TeamTaskBusinessProjectService teamTaskService;
private TeamTaskRepository teamTaskRepository;
private ProductTaskTemplateService productTaskTemplateService;
@Inject
public ProjectGeneratorFactoryTaskTemplate(
ProjectBusinessService projectBusinessService,
ProjectRepository projectRepository,
TeamTaskBusinessProjectService teamTaskService,
TeamTaskRepository teamTaskRepository,
ProductTaskTemplateService productTaskTemplateService) {
this.projectBusinessService = projectBusinessService;
this.projectRepository = projectRepository;
this.teamTaskService = teamTaskService;
this.teamTaskRepository = teamTaskRepository;
this.productTaskTemplateService = productTaskTemplateService;
}
@Override
public Project create(SaleOrder saleOrder) {
Project project = projectBusinessService.generateProject(saleOrder);
project.setIsProject(true);
project.setIsBusinessProject(true);
return project;
}
@Override
@Transactional(rollbackOn = {Exception.class, AxelorException.class})
public ActionViewBuilder fill(Project project, SaleOrder saleOrder, LocalDateTime startDate)
throws AxelorException {
List<TeamTask> tasks = new ArrayList<>();
TeamTask root;
root =
teamTaskRepository
.all()
.filter(
"self.project = ? AND self.assignedTo = ? AND self.name = ?",
project,
project.getAssignedTo(),
saleOrder.getFullName())
.fetchOne();
projectRepository.save(project);
for (SaleOrderLine orderLine : saleOrder.getSaleOrderLineList()) {
Product product = orderLine.getProduct();
if (product != null
&& !((ProductRepository.PROCUREMENT_METHOD_PRODUCE.equals(
product.getProcurementMethodSelect())
|| orderLine.getSaleSupplySelect() == SaleOrderLineRepository.SALE_SUPPLY_PRODUCE)
&& ProductRepository.PRODUCT_TYPE_SERVICE.equals(product.getProductTypeSelect()))) {
continue;
}
boolean isTaskGenerated =
teamTaskRepository
.all()
.filter("self.saleOrderLine = ? AND self.project = ?", orderLine, project)
.fetch()
.size()
> 0;
if (root == null) {
root = teamTaskService.create(saleOrder.getFullName(), project, project.getAssignedTo());
root.setTaskDate(startDate.toLocalDate());
tasks.add(teamTaskRepository.save(root));
}
if (!CollectionUtils.isEmpty(product.getTaskTemplateSet()) && !(isTaskGenerated)) {
List<TeamTask> convertedTasks =
productTaskTemplateService.convert(
product
.getTaskTemplateSet()
.stream()
.filter(template -> Objects.isNull(template.getParentTaskTemplate()))
.collect(Collectors.toList()),
project,
root,
startDate,
orderLine.getQty(),
orderLine);
convertedTasks.stream().forEach(task -> task.setSaleOrderLine(orderLine));
tasks.addAll(convertedTasks);
} else if (CollectionUtils.isEmpty(product.getTaskTemplateSet()) && !(isTaskGenerated)) {
TeamTask childTask =
teamTaskService.create(orderLine.getFullName(), project, project.getAssignedTo());
this.updateTask(root, childTask, orderLine);
tasks.add(teamTaskRepository.save(childTask));
}
}
if (root == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_NO_VALUE,
I18n.get(IExceptionMessage.SALE_ORDER_GENERATE_FILL_PROJECT_ERROR_2));
}
return ActionView.define("Tasks")
.model(TeamTask.class.getName())
.add("grid", "team-task-grid")
.add("form", "team-task-form")
.domain("self.parentTask = " + root.getId());
}
private void updateTask(TeamTask root, TeamTask childTask, SaleOrderLine orderLine) {
childTask.setParentTask(root);
childTask.setQuantity(orderLine.getQty());
Product product = orderLine.getProduct();
childTask.setProduct(product);
childTask.setExTaxTotal(orderLine.getExTaxTotal());
childTask.setUnitPrice(product != null ? product.getSalePrice() : null);
childTask.setUnit(product != null ? product.getUnit() : null);
childTask.setSaleOrderLine(orderLine);
if (orderLine.getSaleOrder().getToInvoiceViaTask()) {
childTask.setToInvoice(true);
childTask.setInvoicingType(TeamTaskRepository.INVOICING_TYPE_PACKAGE);
}
}
}

View File

@ -0,0 +1,23 @@
/*
* 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.businessproject.translation;
public interface ITranslation {
public static final String JOB_COSTING_APP_NAME = /*$$(*/ "value:Job costing"; /*)*/
}

View File

@ -0,0 +1,115 @@
/*
* 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.businessproject.web;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.ExpenseLineProjectService;
import com.axelor.apps.hr.db.ExpenseLine;
import com.axelor.apps.hr.db.repo.ExpenseLineRepository;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.inject.persist.Transactional;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class ExpenseLineProjectController {
/**
* Set project from context selected lines
*
* @param request
* @param response
*/
public void setProject(ActionRequest request, ActionResponse response) {
try {
Project project = request.getContext().asType(Project.class);
project = Beans.get(ProjectRepository.class).find(project.getId());
setProject(request, response, project);
} catch (Exception e) {
TraceBackService.trace(e);
}
}
private void setProject(ActionRequest request, ActionResponse response, Project project) {
List<Map<String, Object>> expenseLineSet =
(List<Map<String, Object>>) request.getContext().get("expenseLineSet");
if (expenseLineSet == null || expenseLineSet.isEmpty()) {
response.setFlash(IExceptionMessage.LINES_NOT_SELECTED);
} else {
List<Long> lineIds =
expenseLineSet
.stream()
.map(it -> Long.parseLong(it.get("id").toString()))
.collect(Collectors.toList());
Beans.get(ExpenseLineProjectService.class).setProject(lineIds, project);
response.setAttr("$expenseLineSet", "hidden", true);
response.setAttr("addSelectedExpenseLinesBtn", "hidden", true);
response.setAttr("unlinkSelectedExpenseLinesBtn", "hidden", true);
response.setAttr("cancelManageExpenseLinesBtn", "hidden", true);
response.setAttr("expenseLinePanel", "refresh", true);
response.setAttr("expensePanel", "refresh", true);
response.setAttr("selectNewExpenseLinesBtn", "readonly", false);
response.setAttr("manageExpenseLinesBtn", "readonly", false);
}
}
/**
* Remove project from selected lines
*
* @param request
* @param response
*/
public void unsetProject(ActionRequest request, ActionResponse response) {
try {
setProject(request, response, null);
} catch (Exception e) {
TraceBackService.trace(e);
}
}
/**
* Invert value of 'toInvoice' field and save the record
*
* @param request
* @param response
*/
@Transactional
public void updateToInvoice(ActionRequest request, ActionResponse response) {
ExpenseLineRepository expenseLineRepository = Beans.get(ExpenseLineRepository.class);
try {
ExpenseLine expenseLine = request.getContext().asType(ExpenseLine.class);
expenseLine = expenseLineRepository.find(expenseLine.getId());
expenseLine.setToInvoice(!expenseLine.getToInvoice());
expenseLineRepository.save(expenseLine);
response.setValue("toInvoice", expenseLine.getToInvoice());
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
}

View File

@ -0,0 +1,330 @@
/*
* 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.businessproject.web;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.PaymentCondition;
import com.axelor.apps.account.db.PaymentMode;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
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.PriceList;
import com.axelor.apps.base.db.Wizard;
import com.axelor.apps.businessproject.service.InvoiceServiceProjectImpl;
import com.axelor.apps.businessproject.service.SaleOrderInvoiceProjectServiceImpl;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.axelor.meta.schema.actions.ActionView;
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.common.base.Joiner;
import com.google.inject.Singleton;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Singleton
public class InvoiceController {
// Generate single invoice from several
@SuppressWarnings({"rawtypes", "unchecked"})
public void mergeInvoice(ActionRequest request, ActionResponse response) {
List<Invoice> invoiceList = new ArrayList<Invoice>();
List<Long> invoiceIdList = new ArrayList<Long>();
boolean fromPopup = false;
if (request.getContext().get("invoiceToMerge") != null) {
if (request.getContext().get("invoiceToMerge") instanceof List) {
// No confirmation popup, invoices are content in a parameter list
List<Map> invoiceMap = (List<Map>) request.getContext().get("invoiceToMerge");
for (Map map : invoiceMap) {
invoiceIdList.add(new Long((Integer) map.get("id")));
}
} else {
// After confirmation popup, invoice's id are in a string separated by ","
String invoiceIdListStr = (String) request.getContext().get("invoiceToMerge");
for (String invoiceId : invoiceIdListStr.split(",")) {
invoiceIdList.add(new Long(invoiceId));
}
fromPopup = true;
}
}
// Check if company, currency and partner are the same for all selected invoices
Company commonCompany = null;
Currency commonCurrency = null;
Partner commonPartner = null;
PaymentCondition commonPaymentCondition = null;
// Useful to determine if a difference exists between payment conditions of all invoices
boolean existPaymentConditionDiff = false;
Partner commonContactPartner = null;
// Useful to determine if a difference exists between contact partners of all purchase orders
boolean existContactPartnerDiff = false;
PriceList commonPriceList = null;
// Useful to determine if a difference exists between price lists of all purchase orders
boolean existPriceListDiff = false;
PaymentMode commonPaymentMode = null;
// Useful to determine if a difference exists between locations of all purchase orders
boolean existPaymentModeDiff = false;
SaleOrder commonSaleOrder = null;
// Useful to check if all sale orders are null (since this field is not required)
boolean saleOrderIsNull = false;
Project commonProject = null;
// Useful to check if all projects are null (since this field is not required)
boolean projectIsNull = false;
Invoice invoiceTemp;
int count = 1;
for (Long invoiceId : invoiceIdList) {
invoiceTemp = JPA.em().find(Invoice.class, invoiceId);
invoiceList.add(invoiceTemp);
if (count == 1) {
commonCompany = invoiceTemp.getCompany();
commonCurrency = invoiceTemp.getCurrency();
commonPartner = invoiceTemp.getPartner();
commonPaymentCondition = invoiceTemp.getPaymentCondition();
commonContactPartner = invoiceTemp.getContactPartner();
commonPriceList = invoiceTemp.getPriceList();
commonPaymentMode = invoiceTemp.getPaymentMode();
commonSaleOrder = invoiceTemp.getSaleOrder();
commonProject = invoiceTemp.getProject();
if (commonSaleOrder == null) {
saleOrderIsNull = true;
}
if (commonProject == null) {
projectIsNull = true;
}
} else {
if (commonCompany != null && !commonCompany.equals(invoiceTemp.getCompany())) {
commonCompany = null;
}
if (commonCurrency != null && !commonCurrency.equals(invoiceTemp.getCurrency())) {
commonCurrency = null;
}
if (commonPartner != null && !commonPartner.equals(invoiceTemp.getPartner())) {
commonPartner = null;
}
if (commonPaymentCondition != null
&& !commonPaymentCondition.equals(invoiceTemp.getPaymentCondition())) {
commonPaymentCondition = null;
existPaymentConditionDiff = true;
}
if (commonContactPartner != null
&& !commonContactPartner.equals(invoiceTemp.getContactPartner())) {
commonContactPartner = null;
existContactPartnerDiff = true;
}
if (commonPriceList != null && !commonPriceList.equals(invoiceTemp.getPriceList())) {
commonPriceList = null;
existPriceListDiff = true;
}
if (commonPaymentMode != null && !commonPaymentMode.equals(invoiceTemp.getPaymentMode())) {
commonPaymentMode = null;
existPaymentModeDiff = true;
}
if (commonSaleOrder != null && !commonSaleOrder.equals(invoiceTemp.getSaleOrder())) {
commonSaleOrder = null;
}
if (commonProject != null && !commonProject.equals(invoiceTemp.getProject())) {
commonProject = null;
}
if (invoiceTemp.getSaleOrder() != null) {
saleOrderIsNull = false;
}
if (invoiceTemp.getProject() != null) {
projectIsNull = false;
}
}
count++;
}
StringBuilder fieldErrors = new StringBuilder();
if (commonCurrency == null) {
fieldErrors.append(I18n.get(IExceptionMessage.INVOICE_MERGE_ERROR_CURRENCY));
}
if (commonCompany == null) {
if (fieldErrors.length() > 0) {
fieldErrors.append("<br/>");
}
fieldErrors.append(I18n.get(IExceptionMessage.INVOICE_MERGE_ERROR_COMPANY));
}
if (commonPartner == null) {
if (fieldErrors.length() > 0) {
fieldErrors.append("<br/>");
}
fieldErrors.append(I18n.get(IExceptionMessage.INVOICE_MERGE_ERROR_PARTNER));
}
if (commonSaleOrder == null && saleOrderIsNull == false) {
if (fieldErrors.length() > 0) {
fieldErrors.append("<br/>");
}
fieldErrors.append(I18n.get(IExceptionMessage.INVOICE_MERGE_ERROR_SALEORDER));
}
if (commonProject == null && projectIsNull == false) {
if (fieldErrors.length() > 0) {
fieldErrors.append("<br/>");
}
fieldErrors.append(I18n.get(IExceptionMessage.INVOICE_MERGE_ERROR_PROJECT));
}
if (fieldErrors.length() > 0) {
response.setFlash(fieldErrors.toString());
return;
}
// Check if contactPartner or priceList or paymentMode or paymentCondition or saleOrder are
// content in parameters
if (request.getContext().get("contactPartner") != null) {
commonContactPartner =
JPA.em()
.find(
Partner.class,
new Long((Integer) ((Map) request.getContext().get("contactPartner")).get("id")));
}
if (request.getContext().get("priceList") != null) {
commonPriceList =
JPA.em()
.find(
PriceList.class,
new Long((Integer) ((Map) request.getContext().get("priceList")).get("id")));
}
if (request.getContext().get("paymentMode") != null) {
commonPaymentMode =
JPA.em()
.find(
PaymentMode.class,
new Long((Integer) ((Map) request.getContext().get("paymentMode")).get("id")));
}
if (request.getContext().get("paymentCondition") != null) {
commonPaymentCondition =
JPA.em()
.find(
PaymentCondition.class,
new Long(
(Integer) ((Map) request.getContext().get("paymentCondition")).get("id")));
}
if (!fromPopup
&& (existPaymentConditionDiff
|| existContactPartnerDiff
|| existPriceListDiff
|| existPaymentModeDiff)) {
// Need to display intermediate screen to select some values
ActionViewBuilder confirmView =
ActionView.define("Confirm merge invoice")
.model(Wizard.class.getName())
.add("form", "customer-invoices-merge-confirm-form")
.param("popup", "true")
.param("show-toolbar", "false")
.param("show-confirm", "false")
.param("popup-save", "false")
.param("forceEdit", "true");
if (existContactPartnerDiff) {
confirmView.context("contextContactPartnerToCheck", "true");
confirmView.context("contextPartnerId", commonPartner.getId().toString());
}
if (existPriceListDiff) {
confirmView.context("contextPriceListToCheck", "true");
}
if (existPaymentModeDiff) {
confirmView.context("contextPaymentModeToCheck", "true");
}
if (existPaymentConditionDiff) {
confirmView.context("contextPaymentConditionToCheck", "true");
}
confirmView.context("invoiceToMerge", Joiner.on(",").join(invoiceIdList));
response.setView(confirmView.map());
return;
}
try {
Invoice invoice =
Beans.get(SaleOrderInvoiceProjectServiceImpl.class)
.mergeInvoice(
invoiceList,
commonCompany,
commonCurrency,
commonPartner,
commonContactPartner,
commonPriceList,
commonPaymentMode,
commonPaymentCondition,
commonSaleOrder,
commonProject);
if (invoice != null) {
// Open the generated invoice in a new tab
response.setView(
ActionView.define("Invoice")
.model(Invoice.class.getName())
.add("grid", "invoice-grid")
.add("form", "invoice-form")
.param("forceEdit", "true")
.context("_showRecord", String.valueOf(invoice.getId()))
.map());
response.setCanClose(true);
}
} catch (Exception e) {
response.setFlash(e.getLocalizedMessage());
}
}
public void exportAnnex(ActionRequest request, ActionResponse response) throws AxelorException {
Invoice invoice =
Beans.get(InvoiceRepository.class).find(request.getContext().asType(Invoice.class).getId());
try {
List<String> reportInfo =
Beans.get(InvoiceServiceProjectImpl.class)
.editInvoiceAnnex(invoice, invoice.getId().toString(), false);
if (reportInfo == null || reportInfo.isEmpty()) {
return;
}
response.setView(ActionView.define(reportInfo.get(0)).add("html", reportInfo.get(1)).map());
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
public void updateLines(ActionRequest request, ActionResponse response) throws AxelorException {
Invoice invoice = request.getContext().asType(Invoice.class);
invoice = Beans.get(InvoiceRepository.class).find(invoice.getId());
for (InvoiceLine invoiceLine : invoice.getInvoiceLineList()) {
invoiceLine.setProject(invoice.getProject());
}
response.setValue("invoiceLineList", invoice.getInvoiceLineList());
}
}

View File

@ -0,0 +1,152 @@
/*
* 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.businessproject.web;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.InvoiceLineProjectService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class InvoiceLineProjectController {
/**
* Set project from context selected lines
*
* @param request
* @param response
*/
public void setCustomerInvoiceLineProject(ActionRequest request, ActionResponse response) {
try {
Project project = request.getContext().asType(Project.class);
project = Beans.get(ProjectRepository.class).find(project.getId());
setCustomerInvoiceLineProject(request, response, project);
} catch (Exception e) {
TraceBackService.trace(e);
}
}
private void setCustomerInvoiceLineProject(
ActionRequest request, ActionResponse response, Project project) {
List<Map<String, Object>> customerInvoiceLineSet =
(List<Map<String, Object>>) request.getContext().get("customerInvoiceLineSet");
if (customerInvoiceLineSet == null || customerInvoiceLineSet.isEmpty()) {
response.setFlash(IExceptionMessage.LINES_NOT_SELECTED);
} else {
List<Long> lineIds =
customerInvoiceLineSet
.stream()
.map(it -> Long.parseLong(it.get("id").toString()))
.collect(Collectors.toList());
Beans.get(InvoiceLineProjectService.class).setProject(lineIds, project);
response.setAttr("$customerInvoiceLineSet", "hidden", true);
response.setAttr("addSelectedCustomerInvoiceLinesBtn", "hidden", true);
response.setAttr("unlinkSelectedCustomerInvoiceLinesBtn", "hidden", true);
response.setAttr("cancelManageCustomerInvoiceLinesBtn", "hidden", true);
response.setAttr("customerInvoiceLinePanel", "refresh", true);
response.setAttr("customerInvoicePanel", "refresh", true);
response.setAttr("selectNewCustomerInvoiceLinesBtn", "readonly", false);
response.setAttr("manageCustomerInvoiceLinesBtn", "readonly", false);
}
}
/**
* Remove project from selected lines
*
* @param request
* @param response
*/
public void unsetCustomerInvoiceLineProject(ActionRequest request, ActionResponse response) {
try {
setCustomerInvoiceLineProject(request, response, null);
} catch (Exception e) {
TraceBackService.trace(e);
}
}
/**
* Set project from context selected lines
*
* @param request
* @param response
*/
public void setSupplierInvoiceLineProject(ActionRequest request, ActionResponse response) {
try {
Project project = request.getContext().asType(Project.class);
project = Beans.get(ProjectRepository.class).find(project.getId());
setSupplierInvoiceLineProject(request, response, project);
} catch (Exception e) {
TraceBackService.trace(e);
}
}
private void setSupplierInvoiceLineProject(
ActionRequest request, ActionResponse response, Project project) {
List<Map<String, Object>> supplierInvoiceLineSet =
(List<Map<String, Object>>) request.getContext().get("supplierInvoiceLineSet");
if (supplierInvoiceLineSet == null || supplierInvoiceLineSet.isEmpty()) {
response.setFlash(IExceptionMessage.LINES_NOT_SELECTED);
} else {
List<Long> lineIds =
supplierInvoiceLineSet
.stream()
.map(it -> Long.parseLong(it.get("id").toString()))
.collect(Collectors.toList());
Beans.get(InvoiceLineProjectService.class).setProject(lineIds, project);
response.setAttr("$supplierInvoiceLineSet", "hidden", true);
response.setAttr("addSelectedSupplierInvoiceLinesBtn", "hidden", true);
response.setAttr("unlinkSelectedSupplierInvoiceLinesBtn", "hidden", true);
response.setAttr("cancelManageSupplierInvoiceLinesBtn", "hidden", true);
response.setAttr("supplierInvoiceLinePanel", "refresh", true);
response.setAttr("supplierInvoicePanel", "refresh", true);
response.setAttr("selectNewSupplierInvoiceLinesBtn", "readonly", false);
response.setAttr("manageSupplierInvoiceLinesBtn", "readonly", false);
}
}
/**
* Remove project from selected lines
*
* @param request
* @param response
*/
public void unsetSupplierInvoiceLineProject(ActionRequest request, ActionResponse response) {
try {
setSupplierInvoiceLineProject(request, response, null);
} catch (Exception e) {
TraceBackService.trace(e);
}
}
}

View File

@ -0,0 +1,100 @@
/*
* 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.businessproject.web;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.businessproject.db.InvoicingProject;
import com.axelor.apps.businessproject.db.repo.InvoicingProjectRepository;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.InvoicingProjectService;
import com.axelor.apps.project.db.Project;
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.schema.actions.ActionView;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.inject.Singleton;
import java.io.IOException;
@Singleton
public class InvoicingProjectController {
public void generateInvoice(ActionRequest request, ActionResponse response)
throws AxelorException {
InvoicingProject invoicingProject = request.getContext().asType(InvoicingProject.class);
invoicingProject = Beans.get(InvoicingProjectRepository.class).find(invoicingProject.getId());
if (invoicingProject.getSaleOrderLineSet().isEmpty()
&& invoicingProject.getPurchaseOrderLineSet().isEmpty()
&& invoicingProject.getLogTimesSet().isEmpty()
&& invoicingProject.getExpenseLineSet().isEmpty()
&& invoicingProject.getProjectSet().isEmpty()
&& invoicingProject.getTeamTaskSet().isEmpty()) {
throw new AxelorException(
invoicingProject,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.INVOICING_PROJECT_EMPTY));
}
if (invoicingProject.getProject() == null) {
throw new AxelorException(
invoicingProject,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.INVOICING_PROJECT_PROJECT));
}
if (invoicingProject.getProject().getClientPartner() == null) {
throw new AxelorException(
invoicingProject,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.INVOICING_PROJECT_PROJECT_PARTNER));
}
Invoice invoice = Beans.get(InvoicingProjectService.class).generateInvoice(invoicingProject);
try {
if (invoice != null) {
Beans.get(InvoicingProjectService.class).generateAnnex(invoicingProject);
}
} catch (IOException e) {
TraceBackService.trace(e);
}
response.setReload(true);
response.setView(
ActionView.define("Invoice")
.model(Invoice.class.getName())
.add("form", "invoice-form")
.param("forceEdit", "true")
.context("_showRecord", String.valueOf(invoice.getId()))
.map());
}
public void fillIn(ActionRequest request, ActionResponse response) throws AxelorException {
InvoicingProject invoicingProject = request.getContext().asType(InvoicingProject.class);
InvoicingProjectService invoicingProjectService = Beans.get(InvoicingProjectService.class);
Project project = invoicingProject.getProject();
if (project == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.INVOICING_PROJECT_PROJECT));
}
invoicingProjectService.clearLines(invoicingProject);
invoicingProjectService.setLines(invoicingProject, project, 0);
response.setValues(invoicingProject);
}
}

View File

@ -0,0 +1,184 @@
/*
* 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.businessproject.web;
import com.axelor.apps.ReportFactory;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.PriceListRepository;
import com.axelor.apps.base.service.PartnerPriceListService;
import com.axelor.apps.businessproject.db.InvoicingProject;
import com.axelor.apps.businessproject.report.IReport;
import com.axelor.apps.businessproject.service.InvoicingProjectService;
import com.axelor.apps.businessproject.service.ProjectBusinessService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.apps.purchase.db.PurchaseOrder;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.exception.AxelorException;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.axelor.meta.schema.actions.ActionView;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.inject.Singleton;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Singleton
public class ProjectController {
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
public void generateQuotation(ActionRequest request, ActionResponse response) {
try {
Project project = request.getContext().asType(Project.class);
SaleOrder order = Beans.get(ProjectBusinessService.class).generateQuotation(project);
response.setView(
ActionView.define("Sale Order")
.model(SaleOrder.class.getName())
.add("form", "sale-order-form")
.context("_showRecord", String.valueOf(order.getId()))
.map());
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
public void generatePurchaseQuotation(ActionRequest request, ActionResponse response) {
Project project = request.getContext().asType(Project.class);
if (project.getId() != null) {
response.setView(
ActionView.define("Purchase Order")
.model(PurchaseOrder.class.getName())
.add("form", "purchase-order-form")
.add("grid", "purchase-order-quotation-grid")
.context("_project", Beans.get(ProjectRepository.class).find(project.getId()))
.map());
}
}
public void printProject(ActionRequest request, ActionResponse response) throws AxelorException {
Project project = request.getContext().asType(Project.class);
String name = I18n.get("Project") + " " + (project.getCode() != null ? project.getCode() : "");
String fileLink =
ReportFactory.createReport(IReport.PROJECT, name + "-${date}")
.addParam("ProjectId", project.getId())
.addParam("Locale", ReportSettings.getPrintingLocale(null))
.toAttach(project)
.generate()
.getFileLink();
logger.debug("Printing " + name);
response.setView(ActionView.define(name).add("html", fileLink).map());
}
// TODO: Duration is removed. Have to change calcuation
public void computeProgress(ActionRequest request, ActionResponse response) {
// Project project = request.getContext().asType(Project.class);
BigDecimal duration = BigDecimal.ZERO;
// if (BigDecimal.ZERO.compareTo(project.getDuration()) != 0) {
// duration =
// project
// .getTimeSpent()
// .add(project.getLeadDelay())
// .divide(project.getDuration(), 2, java.math.RoundingMode.HALF_UP)
// .multiply(new BigDecimal(100));
// }
if (duration.compareTo(BigDecimal.ZERO) == -1 || duration.compareTo(new BigDecimal(100)) == 1) {
duration = BigDecimal.ZERO;
}
response.setValue("progress", duration);
}
public void countToInvoice(ActionRequest request, ActionResponse response) {
Project project = request.getContext().asType(Project.class);
int toInvoiceCount = 0;
if (project.getId() != null) {
toInvoiceCount = Beans.get(InvoicingProjectService.class).countToInvoice(project);
}
response.setValue("$toInvoiceCounter", toInvoiceCount);
}
public void showInvoicingProjects(ActionRequest request, ActionResponse response) {
Project project = request.getContext().asType(Project.class);
project = Beans.get(ProjectRepository.class).find(project.getId());
response.setView(
ActionView.define("Invoice Buisness Project")
.model(InvoicingProject.class.getName())
.add("form", "invoicing-project-form")
.param("forceEdit", "true")
.param("show-toolbar", "false")
.context("_project", project)
.map());
}
public void printPlannifAndCost(ActionRequest request, ActionResponse response)
throws AxelorException {
Project project = request.getContext().asType(Project.class);
String name = I18n.get("Planification and costs");
if (project.getCode() != null) {
name += " (" + project.getCode() + ")";
}
String fileLink =
ReportFactory.createReport(IReport.PLANNIF_AND_COST, name)
.addParam("ProjectId", project.getId())
.addParam("Locale", ReportSettings.getPrintingLocale(null))
.toAttach(project)
.generate()
.getFileLink();
response.setView(ActionView.define(name).add("html", fileLink).map());
}
public void getPartnerData(ActionRequest request, ActionResponse response) {
Project project = request.getContext().asType(Project.class);
Partner partner = project.getClientPartner();
if (partner != null) {
response.setValue("currency", partner.getCurrency());
response.setValue(
"priceList",
project.getClientPartner() != null
? Beans.get(PartnerPriceListService.class)
.getDefaultPriceList(project.getClientPartner(), PriceListRepository.TYPE_SALE)
: null);
}
}
}

View File

@ -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.businessproject.web;
import com.axelor.apps.businessproject.report.ITranslation;
import com.axelor.apps.businessproject.service.ProjectFolderService;
import com.axelor.apps.project.db.ProjectFolder;
import com.axelor.exception.AxelorException;
import com.axelor.exception.ResponseMessageType;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.axelor.meta.schema.actions.ActionView;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.inject.Singleton;
@Singleton
public class ProjectFolderController {
public void printProjectsPlanificationAndCost(ActionRequest request, ActionResponse response)
throws AxelorException {
ProjectFolder projectFolder = request.getContext().asType(ProjectFolder.class);
String fileLink;
String title;
try {
fileLink =
Beans.get(ProjectFolderService.class).printProjectsPlanificationAndCost(projectFolder);
title = I18n.get(ITranslation.PROJECT_REPORT_TITLE_FOR_PLANIFICATION_AND_COST);
response.setView(ActionView.define(title).add("html", fileLink).map());
} catch (Exception e) {
TraceBackService.trace(response, e, ResponseMessageType.ERROR);
}
}
public void printProjectsFinancialReport(ActionRequest request, ActionResponse response)
throws AxelorException {
ProjectFolder projectFolder = request.getContext().asType(ProjectFolder.class);
String fileLink;
String title;
try {
fileLink = Beans.get(ProjectFolderService.class).printProjectFinancialReport(projectFolder);
title = I18n.get(ITranslation.PROJECT_REPORT_TITLE_FOR_FINANCIAL);
response.setView(ActionView.define(title).add("html", fileLink).map());
} catch (Exception e) {
TraceBackService.trace(response, e, ResponseMessageType.ERROR);
}
}
}

View File

@ -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.businessproject.web;
import com.axelor.apps.base.db.Batch;
import com.axelor.apps.base.db.repo.BatchRepository;
import com.axelor.apps.businessproject.db.InvoicingProject;
import com.axelor.apps.businessproject.db.ProjectInvoicingAssistantBatch;
import com.axelor.apps.businessproject.db.repo.ProjectInvoicingAssistantBatchRepository;
import com.axelor.apps.businessproject.service.batch.ProjectInvoicingAssistantBatchService;
import com.axelor.apps.hr.db.TimesheetLine;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.axelor.meta.schema.actions.ActionView;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.axelor.team.db.TeamTask;
import java.util.HashMap;
import java.util.Map;
public class ProjectInvoicingAssistantBatchController {
public void actionUpdateTask(ActionRequest request, ActionResponse response) {
try {
ProjectInvoicingAssistantBatch projectInvoicingAssistantBatch =
request.getContext().asType(ProjectInvoicingAssistantBatch.class);
projectInvoicingAssistantBatch =
Beans.get(ProjectInvoicingAssistantBatchRepository.class)
.find(projectInvoicingAssistantBatch.getId());
Batch batch =
Beans.get(ProjectInvoicingAssistantBatchService.class)
.updateTask(projectInvoicingAssistantBatch);
response.setFlash(batch.getComments());
} catch (Exception e) {
TraceBackService.trace(response, e);
} finally {
response.setReload(true);
}
}
public void showUpdatedTask(ActionRequest request, ActionResponse response) {
try {
Map<String, Object> values = new HashMap<String, Object>();
values.put("field", "updatedTaskSet");
values.put("title", I18n.get("Updated tasks"));
values.put("model", TeamTask.class.getName());
values.put("grid", "business-project-team-task-grid");
values.put("form", "team-task-form");
this.showRecords(request, response, values);
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
public void showUpdatedTimesheetLine(ActionRequest request, ActionResponse response) {
try {
Map<String, Object> values = new HashMap<String, Object>();
values.put("field", "updatedTimesheetLineSet");
values.put("title", I18n.get("Updated timesheet lines"));
values.put("model", TimesheetLine.class.getName());
values.put("grid", "timesheet-line-project-grid");
values.put("form", "timesheet-line-project-form");
this.showRecords(request, response, values);
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
public void actionGenerateInvoicingProject(ActionRequest request, ActionResponse response) {
try {
ProjectInvoicingAssistantBatch projectInvoicingAssistantBatch =
request.getContext().asType(ProjectInvoicingAssistantBatch.class);
projectInvoicingAssistantBatch =
Beans.get(ProjectInvoicingAssistantBatchRepository.class)
.find(projectInvoicingAssistantBatch.getId());
Batch batch =
Beans.get(ProjectInvoicingAssistantBatchService.class)
.generateInvoicingProject(projectInvoicingAssistantBatch);
response.setFlash(batch.getComments());
} catch (Exception e) {
TraceBackService.trace(response, e);
} finally {
response.setReload(true);
}
}
public void showGeneratedInvoicingProject(ActionRequest request, ActionResponse response) {
try {
Map<String, Object> values = new HashMap<String, Object>();
values.put("field", "generatedInvoicingProjectSet");
values.put("title", I18n.get("Generated invoicing projects"));
values.put("model", InvoicingProject.class.getName());
values.put("grid", "invoicing-project-grid");
values.put("form", "invoicing-project-form");
this.showRecords(request, response, values);
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
private void showRecords(
ActionRequest request, ActionResponse response, Map<String, Object> values)
throws ClassNotFoundException {
Batch batch = request.getContext().asType(Batch.class);
batch = Beans.get(BatchRepository.class).find(batch.getId());
String ids =
Beans.get(ProjectInvoicingAssistantBatchService.class)
.getShowRecordIds(batch, values.get("field").toString());
response.setView(
ActionView.define(values.get("title").toString())
.model(values.get("model").toString())
.add("grid", values.get("grid").toString())
.add("form", values.get("form").toString())
.domain("self.id IN (" + ids + ")")
.map());
}
}

View File

@ -0,0 +1,117 @@
/*
* 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.businessproject.web;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.PurchaseOrderLineProjectService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.apps.purchase.db.PurchaseOrderLine;
import com.axelor.apps.purchase.db.repo.PurchaseOrderLineRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.inject.persist.Transactional;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class PurchaseOrderLineProjectController {
/**
* Set project from context selected lines
*
* @param request
* @param response
*/
public void setProject(ActionRequest request, ActionResponse response) {
try {
Project project = request.getContext().asType(Project.class);
project = Beans.get(ProjectRepository.class).find(project.getId());
setProject(request, response, project);
} catch (Exception e) {
TraceBackService.trace(e);
}
}
private void setProject(ActionRequest request, ActionResponse response, Project project) {
List<Map<String, Object>> purchaseOrderLineSet =
(List<Map<String, Object>>) request.getContext().get("purchaseOrderLineSet");
if (purchaseOrderLineSet == null || purchaseOrderLineSet.isEmpty()) {
response.setFlash(IExceptionMessage.LINES_NOT_SELECTED);
} else {
List<Long> lineIds =
purchaseOrderLineSet
.stream()
.map(it -> Long.parseLong(it.get("id").toString()))
.collect(Collectors.toList());
Beans.get(PurchaseOrderLineProjectService.class).setProject(lineIds, project);
response.setAttr("$purchaseOrderLineSet", "hidden", true);
response.setAttr("addSelectedPOLinesBtn", "hidden", true);
response.setAttr("unlinkSelectedPOLinesBtn", "hidden", true);
response.setAttr("cancelManagePOLinesBtn", "hidden", true);
response.setAttr("purchaseOrderLinePanel", "refresh", true);
response.setAttr("purchaseOrderPanel", "refresh", true);
response.setAttr("selectNewPOLinesBtn", "readonly", false);
response.setAttr("managePOLinesBtn", "readonly", false);
}
}
/**
* Remove project from selected lines
*
* @param request
* @param response
*/
public void unsetProject(ActionRequest request, ActionResponse response) {
try {
setProject(request, response, null);
} catch (Exception e) {
TraceBackService.trace(e);
}
}
/**
* Invert value of 'toInvoice' field and save the record
*
* @param request
* @param response
*/
@Transactional
public void updateToInvoice(ActionRequest request, ActionResponse response) {
PurchaseOrderLineRepository purchaseOrderLineRepository =
Beans.get(PurchaseOrderLineRepository.class);
try {
PurchaseOrderLine purchaseOrderLine = request.getContext().asType(PurchaseOrderLine.class);
purchaseOrderLine = purchaseOrderLineRepository.find(purchaseOrderLine.getId());
purchaseOrderLine.setToInvoice(!purchaseOrderLine.getToInvoice());
purchaseOrderLineRepository.save(purchaseOrderLine);
response.setValue("toInvoice", purchaseOrderLine.getToInvoice());
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
}

View File

@ -0,0 +1,41 @@
/*
* 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.businessproject.web;
import com.axelor.apps.purchase.db.PurchaseOrder;
import com.axelor.apps.purchase.db.PurchaseOrderLine;
import com.axelor.apps.purchase.db.repo.PurchaseOrderRepository;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.inject.Singleton;
@Singleton
public class PurchaseOrderProjectController {
public void updateLines(ActionRequest request, ActionResponse response) throws AxelorException {
PurchaseOrder purchaseOrder = request.getContext().asType(PurchaseOrder.class);
purchaseOrder = Beans.get(PurchaseOrderRepository.class).find(purchaseOrder.getId());
for (PurchaseOrderLine orderLine : purchaseOrder.getPurchaseOrderLineList()) {
orderLine.setProject(purchaseOrder.getProject());
}
response.setValue("purchaseOrderLineList", purchaseOrder.getPurchaseOrderLineList());
}
}

View File

@ -0,0 +1,114 @@
/*
* 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.businessproject.web;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.SaleOrderLineProjectService;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.repo.ProjectRepository;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderLineRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.google.inject.persist.Transactional;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class SaleOrderLineProjectController {
/**
* Set project from context selected lines
*
* @param request
* @param response
*/
public void setProject(ActionRequest request, ActionResponse response) {
try {
Project project = request.getContext().asType(Project.class);
project = Beans.get(ProjectRepository.class).find(project.getId());
setProject(request, response, project);
} catch (Exception e) {
TraceBackService.trace(e);
}
}
private void setProject(ActionRequest request, ActionResponse response, Project project) {
List<Map<String, Object>> saleOrderLineSet =
(List<Map<String, Object>>) request.getContext().get("salesOrderLineSet");
if (saleOrderLineSet == null || saleOrderLineSet.isEmpty()) {
response.setFlash(IExceptionMessage.LINES_NOT_SELECTED);
} else {
List<Long> lineIds =
saleOrderLineSet
.stream()
.map(it -> Long.parseLong(it.get("id").toString()))
.collect(Collectors.toList());
Beans.get(SaleOrderLineProjectService.class).setProject(lineIds, project);
response.setAttr("$salesOrderLineSet", "hidden", true);
response.setAttr("addSelectedSOLinesBtn", "hidden", true);
response.setAttr("unlinkSelectedSOLinesBtn", "hidden", true);
response.setAttr("cancelManageSOLinesBtn", "hidden", true);
response.setAttr("saleOrderLinePanel", "refresh", true);
response.setAttr("saleOrderPanel", "refresh", true);
response.setAttr("selectNewSOLinesBtn", "readonly", false);
response.setAttr("manageSOLinesBtn", "readonly", false);
}
}
/**
* Remove project from selected lines
*
* @param request
* @param response
*/
public void unsetProject(ActionRequest request, ActionResponse response) {
try {
setProject(request, response, null);
} catch (Exception e) {
TraceBackService.trace(e);
}
}
/**
* Invert value of 'toInvoice' field and save the record
*
* @param request
* @param response
*/
@Transactional
public void updateToInvoice(ActionRequest request, ActionResponse response) {
SaleOrderLineRepository saleOrderLineRepository = Beans.get(SaleOrderLineRepository.class);
try {
SaleOrderLine saleOrderLine = request.getContext().asType(SaleOrderLine.class);
saleOrderLine = saleOrderLineRepository.find(saleOrderLine.getId());
saleOrderLine.setToInvoice(!saleOrderLine.getToInvoice());
saleOrderLineRepository.save(saleOrderLine);
response.setValue("toInvoice", saleOrderLine.getToInvoice());
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
}

View File

@ -0,0 +1,132 @@
/*
* 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.businessproject.web;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.businessproject.exception.IExceptionMessage;
import com.axelor.apps.businessproject.service.projectgenerator.ProjectGeneratorFactory;
import com.axelor.apps.project.db.Project;
import com.axelor.apps.project.db.ProjectGeneratorType;
import com.axelor.apps.sale.db.SaleOrder;
import com.axelor.apps.sale.db.SaleOrderLine;
import com.axelor.apps.sale.db.repo.SaleOrderRepository;
import com.axelor.exception.AxelorException;
import com.axelor.exception.ResponseMessageType;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.axelor.meta.schema.actions.ActionView;
import com.axelor.meta.schema.actions.ActionView.ActionViewBuilder;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.axelor.rpc.Context;
import com.google.common.base.Strings;
import com.google.inject.Singleton;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
@Singleton
public class SaleOrderProjectController {
private static final String CONTEXT_SHOW_RECORD = "_showRecord";
public void generateProject(ActionRequest request, ActionResponse response) {
try {
SaleOrder saleOrder = request.getContext().asType(SaleOrder.class);
saleOrder = Beans.get(SaleOrderRepository.class).find(saleOrder.getId());
if (saleOrder.getSaleOrderLineList() == null || saleOrder.getSaleOrderLineList().isEmpty()) {
response.setAlert(I18n.get(IExceptionMessage.SALE_ORDER_GENERATE_FILL_PROJECT_ERROR_2));
return;
}
String generatorType = (String) request.getContext().get("_projectGeneratorType");
LocalDateTime startDate = getElementStartDate(request.getContext());
ProjectGeneratorType projectGeneratorType = ProjectGeneratorType.valueOf(generatorType);
ProjectGeneratorFactory factory = ProjectGeneratorFactory.getFactory(projectGeneratorType);
Project project;
if (projectGeneratorType.equals(ProjectGeneratorType.PROJECT_ALONE)) {
project = factory.create(saleOrder);
} else {
project = factory.generate(saleOrder, startDate);
}
response.setReload(true);
response.setView(
ActionView.define("Project")
.model(Project.class.getName())
.add("form", "project-form")
.param("forceEdit", "true")
.context(CONTEXT_SHOW_RECORD, String.valueOf(project.getId()))
.map());
} catch (Exception e) {
TraceBackService.trace(response, e, ResponseMessageType.ERROR);
response.setReload(true);
}
}
public void fillProject(ActionRequest request, ActionResponse response) {
try {
SaleOrder saleOrder = request.getContext().asType(SaleOrder.class);
saleOrder = Beans.get(SaleOrderRepository.class).find(saleOrder.getId());
if (saleOrder.getSaleOrderLineList() == null
|| (saleOrder.getSaleOrderLineList() != null
&& saleOrder.getSaleOrderLineList().isEmpty())) {
response.setAlert(I18n.get(IExceptionMessage.SALE_ORDER_GENERATE_FILL_PROJECT_ERROR_2));
return;
}
String generatorType = (String) request.getContext().get("_projectGeneratorType");
LocalDateTime startDate = getElementStartDate(request.getContext());
ProjectGeneratorFactory factory =
ProjectGeneratorFactory.getFactory(ProjectGeneratorType.valueOf(generatorType));
ActionViewBuilder view = factory.fill(saleOrder.getProject(), saleOrder, startDate);
response.setReload(true);
response.setView(view.map());
} catch (Exception e) {
TraceBackService.trace(response, e);
response.setReload(true);
}
}
public void updateLines(ActionRequest request, ActionResponse response) throws AxelorException {
SaleOrder saleOrder = request.getContext().asType(SaleOrder.class);
saleOrder = Beans.get(SaleOrderRepository.class).find(saleOrder.getId());
for (SaleOrderLine orderLine : saleOrder.getSaleOrderLineList()) {
orderLine.setProject(saleOrder.getProject());
}
response.setValue("saleOrderLineList", saleOrder.getSaleOrderLineList());
}
private LocalDateTime getElementStartDate(Context context) {
LocalDateTime date;
String stringStartDate = (String) context.get("_elementStartDate");
if (!Strings.isNullOrEmpty(stringStartDate)) {
date = LocalDateTime.ofInstant(Instant.parse(stringStartDate), ZoneId.systemDefault());
} else {
date = Beans.get(AppBaseService.class).getTodayDate().atStartOfDay();
}
return date;
}
}

View File

@ -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.businessproject.web;
import com.axelor.apps.businessproject.service.TeamTaskBusinessProjectService;
import com.axelor.apps.project.db.TeamTaskCategory;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
import com.axelor.team.db.TeamTask;
import com.axelor.team.db.repo.TeamTaskRepository;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
public class TeamTaskController {
@Inject private TeamTaskBusinessProjectService businessProjectService;
public void updateDiscount(ActionRequest request, ActionResponse response) {
TeamTask teamTask = request.getContext().asType(TeamTask.class);
if (teamTask.getProduct() == null || teamTask.getProject() == null) {
return;
}
try {
teamTask = Beans.get(TeamTaskBusinessProjectService.class).updateDiscount(teamTask);
response.setValue("discountTypeSelect", teamTask.getDiscountTypeSelect());
response.setValue("discountAmount", teamTask.getDiscountAmount());
response.setValue("priceDiscounted", teamTask.getPriceDiscounted());
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
public void compute(ActionRequest request, ActionResponse response) {
TeamTask teamTask = request.getContext().asType(TeamTask.class);
try {
teamTask = Beans.get(TeamTaskBusinessProjectService.class).compute(teamTask);
response.setValue("priceDiscounted", teamTask.getPriceDiscounted());
response.setValue("exTaxTotal", teamTask.getExTaxTotal());
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
/**
* Invert value of 'toInvoice' field and save the record
*
* @param request
* @param response
*/
@Transactional
public void updateToInvoice(ActionRequest request, ActionResponse response) {
TeamTaskRepository teamTaskRepository = Beans.get(TeamTaskRepository.class);
try {
TeamTask teamTask = request.getContext().asType(TeamTask.class);
teamTask = teamTaskRepository.find(teamTask.getId());
teamTask.setToInvoice(!teamTask.getToInvoice());
teamTaskRepository.save(teamTask);
response.setValue("toInvoice", teamTask.getToInvoice());
} catch (Exception e) {
TraceBackService.trace(response, e);
}
}
public void onChangeCategory(ActionRequest request, ActionResponse response) {
TeamTask task = request.getContext().asType(TeamTask.class);
TeamTaskCategory teamTaskCategory = task.getTeamTaskCategory();
task = businessProjectService.resetTeamTaskValues(task);
if (teamTaskCategory != null) {
task = businessProjectService.computeDefaultInformation(task);
}
if (task.getInvoicingType() == TeamTaskRepository.INVOICING_TYPE_TIME_SPENT) {
task.setToInvoice(true);
}
response.setValues(task);
}
}

View File

@ -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.businessproject.web;
import com.axelor.apps.businessproject.service.TimesheetLineBusinessService;
import com.axelor.apps.hr.db.TimesheetLine;
import com.axelor.inject.Beans;
import com.axelor.rpc.ActionRequest;
import com.axelor.rpc.ActionResponse;
public class TimesheetLineBusinessController {
public void setDefaultToInvoice(ActionRequest request, ActionResponse response) {
TimesheetLine timesheetLine = request.getContext().asType(TimesheetLine.class);
timesheetLine =
Beans.get(TimesheetLineBusinessService.class).getDefaultToInvoice(timesheetLine);
response.setValue("toInvoice", timesheetLine.getToInvoice());
}
}

View File

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8"?>
<csv-inputs xmlns="http://axelor.com/xml/ns/data-import"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/data-import http://axelor.com/xml/ns/data-import/data-import_5.2.xsd">
<input file="auth_permission.csv" separator=";" type="com.axelor.auth.db.Permission" search="self.name = :name" call="com.axelor.csv.script.ImportPermission:importPermissionToRole">
<bind to="canRead" eval="can_read == 'x' ? 'true' : 'false'"/>
<bind to="canWrite" eval="can_write == 'x' ? 'true' : 'false'"/>
<bind to="canCreate" eval="can_create == 'x' ? 'true' : 'false'"/>
<bind to="canRemove" eval="can_remove == 'x' ? 'true' : 'false'"/>
<bind to="canExport" eval="can_export == 'x' ? 'true' : 'false'"/>
</input>
<input file="base_appBusinessProject.csv" separator=";" type="com.axelor.apps.base.db.AppBusinessProject" call="com.axelor.csv.script.ImportApp:importApp">
<bind column="dependsOn" to="dependsOnSet" search="self.code in :dependsOn" eval="dependsOn.split(',') as List"/>
</input>
<input file="meta_helpEN.csv" separator=";" type="com.axelor.meta.db.MetaHelp">
<bind to="language" eval="'en'" />
<bind to="type" eval="'tooltip'" />
<bind to="model" eval="com.axelor.inject.Beans.get(com.axelor.meta.db.repo.MetaModelRepository.class).findByName(object)?.getFullName()" column="object" />
</input>
<input file="meta_helpFR.csv" separator=";" type="com.axelor.meta.db.MetaHelp">
<bind to="language" eval="'fr'" />
<bind to="type" eval="'tooltip'" />
<bind to="model" eval="com.axelor.inject.Beans.get(com.axelor.meta.db.repo.MetaModelRepository.class).findByName(object)?.getFullName()" column="object" />
</input>
<input file="meta_metaMenu.csv" separator=";" type="com.axelor.meta.db.MetaMenu" search="self.name = :name" update="true" />
<input file="meta_metaJsonField.csv" separator=";" type="com.axelor.meta.db.MetaJsonField"
search="self.name = :name and self.model = :model and self.modelField = :modelField and self.jsonModel is null"
call="com.axelor.studio.service.ImportService:importJsonField">
<bind to="name" column="name"/>
<bind to="title" column="title"/>
<bind to="type" column="type"/>
<bind to="model" column="model"/>
<bind to="modelField" column="modelField"/>
<bind to="targetModel" column="targetModel"/>
<bind to="sequence" column="sequence"/>
<bind to="onClick" column="onClick"/>
<bind to="gridView" column="gridView"/>
<bind to="formView" column="formView"/>
<bind to="widgetAttrs" column="widgetAttrs"/>
<bind to="showIf" column="showIf"/>
</input>
</csv-inputs>

View File

@ -0,0 +1,2 @@
"name";"object";"can_read";"can_write";"can_create";"can_remove";"can_export";"condition";"conditionParams";"roleName"
"perm.businessproject.all";"com.axelor.apps.businessproject.db.*";"x";"x";"x";"x";"x";;;"Admin"
1 name object can_read can_write can_create can_remove can_export condition conditionParams roleName
2 perm.businessproject.all com.axelor.apps.businessproject.db.* x x x x x Admin

View File

@ -0,0 +1,2 @@
"name";"code";"installOrder";"description";"imagePath";"modules";"dependsOn";"sequence"
"Job costing";"business-project";17;"Job costing";"app-business-project.png";"axelor-business-project";"project,employee,supplychain";12
1 name code installOrder description imagePath modules dependsOn sequence
2 Job costing business-project 17 Job costing app-business-project.png axelor-business-project project,employee,supplychain 12

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

View File

@ -0,0 +1,22 @@
"module";"object";"view";"field";"help"
"axelor-business-project";"SaleOrder";"sale-order-form";"manualUnblock";"If a customer is blocked, you can manually unblock it by clicking on this check-box."
"axelor-business-project";"SaleOrder";"sale-order-form";"saleOrderSeq";"Internal reference number for the order, generated when the order is saved for the first time. "
"axelor-business-project";"SaleOrder";"sale-order-form";"priceList";"Enables to attach a price list to be used for this particular order. This field is automatically filled in if a price list is attached to the partner."
"axelor-business-project";"SaleOrder";"sale-order-form";"project";"Enables to select a project to which the order will be attached. This function, useful for business project management, will allow to invoice the order (when invoicing the business project), as well as other elements."
"axelor-business-project";"SaleOrder";"sale-order-form";"expectedRealisationDate";"Enables to specify an estimated payment date for the invoice, which will be generated from the order. "
"axelor-business-project";"SaleOrder";"sale-order-form";"hideDiscount";"Checkbox to check for not showing the details of the discounts on the printings of the quotations/orders."
"axelor-business-project";"SaleOrder";"sale-order-template-form";"createOrder";"This button generates a new draft of customer quotation from the selected model. "
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"generateProjectOrder";"This option allows you to select a project on an order as part of the job costing management. The order will be attached to a business project, on which you can invoice the order lines."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"automaticProject";"If this option is enabled, a project will be automatically generated at each sales order confirmation."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"projectSaleOrderLines";"This option allows you to activate a project tab in the sale order lines, which will allow to select a business project and indicate whether the order line should be invoiced in the business project. It is therefore an essential option for invoicing order lines in a business project."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"projectPurchaseOrderLines";"This option allows you to activate a project tab in the purchase order lines, which will allow to select a business project and indicate whether the order line should be invoiced in the business project. It is therefore an essential option for invoicing order lines in a business project."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"projectInvoiceLines";"This option allows you to activate a project tab in the invoice lines, which will link the invoices to the business project."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"productInvoicingProject";"Allow to define a default invoicing product on business projects, when these are invoiced on a flat rate basis."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showPurchaseOrderLineRelatedToProject";"By enabling this option, you will display the purchase order lines attached to a business project, in the ""Related elements"" tab of a business project."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showSaleOrderLineRelatedToProject";"By enabling this option, you will display the sale order lines attached to a business project, in the ""Related elements"" tab of a business project."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showProductionOrderRelatedToProject";"By enabling this option, you will display the production orders attached to a business project, in the ""Related elements"" tab of a business project."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showExpenseLineRelatedToProject";"By enabling this option, you will display the expenses attached to a business project, in the ""Related elements"" tab of a business project."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showPurchaseInvoiceLineRelatedToProject";"By enabling this option, you will display the purchase invoice lines attached to a business project, in the ""Related elements"" tab of a business project."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showSaleInvoiceLineRelatedToProject";"By enabling this option, you will display the sale invoice lines attached to a business project, in the ""Related elements"" tab of a business project."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"enableToInvoiceTimesheet";"This option allows invoicing of timesheets in business projects."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"enableToInvoiceExpense";"This option allows invoicing of expenses in business projects."
1 module object view field help
2 axelor-business-project SaleOrder sale-order-form manualUnblock If a customer is blocked, you can manually unblock it by clicking on this check-box.
3 axelor-business-project SaleOrder sale-order-form saleOrderSeq Internal reference number for the order, generated when the order is saved for the first time.
4 axelor-business-project SaleOrder sale-order-form priceList Enables to attach a price list to be used for this particular order. This field is automatically filled in if a price list is attached to the partner.
5 axelor-business-project SaleOrder sale-order-form project Enables to select a project to which the order will be attached. This function, useful for business project management, will allow to invoice the order (when invoicing the business project), as well as other elements.
6 axelor-business-project SaleOrder sale-order-form expectedRealisationDate Enables to specify an estimated payment date for the invoice, which will be generated from the order.
7 axelor-business-project SaleOrder sale-order-form hideDiscount Checkbox to check for not showing the details of the discounts on the printings of the quotations/orders.
8 axelor-business-project SaleOrder sale-order-template-form createOrder This button generates a new draft of customer quotation from the selected model.
9 axelor-business-project AppBusinessProject app-business-project-config-form generateProjectOrder This option allows you to select a project on an order as part of the job costing management. The order will be attached to a business project, on which you can invoice the order lines.
10 axelor-business-project AppBusinessProject app-business-project-config-form automaticProject If this option is enabled, a project will be automatically generated at each sales order confirmation.
11 axelor-business-project AppBusinessProject app-business-project-config-form projectSaleOrderLines This option allows you to activate a project tab in the sale order lines, which will allow to select a business project and indicate whether the order line should be invoiced in the business project. It is therefore an essential option for invoicing order lines in a business project.
12 axelor-business-project AppBusinessProject app-business-project-config-form projectPurchaseOrderLines This option allows you to activate a project tab in the purchase order lines, which will allow to select a business project and indicate whether the order line should be invoiced in the business project. It is therefore an essential option for invoicing order lines in a business project.
13 axelor-business-project AppBusinessProject app-business-project-config-form projectInvoiceLines This option allows you to activate a project tab in the invoice lines, which will link the invoices to the business project.
14 axelor-business-project AppBusinessProject app-business-project-config-form productInvoicingProject Allow to define a default invoicing product on business projects, when these are invoiced on a flat rate basis.
15 axelor-business-project AppBusinessProject app-business-project-config-form showPurchaseOrderLineRelatedToProject By enabling this option, you will display the purchase order lines attached to a business project, in the "Related elements" tab of a business project.
16 axelor-business-project AppBusinessProject app-business-project-config-form showSaleOrderLineRelatedToProject By enabling this option, you will display the sale order lines attached to a business project, in the "Related elements" tab of a business project.
17 axelor-business-project AppBusinessProject app-business-project-config-form showProductionOrderRelatedToProject By enabling this option, you will display the production orders attached to a business project, in the "Related elements" tab of a business project.
18 axelor-business-project AppBusinessProject app-business-project-config-form showExpenseLineRelatedToProject By enabling this option, you will display the expenses attached to a business project, in the "Related elements" tab of a business project.
19 axelor-business-project AppBusinessProject app-business-project-config-form showPurchaseInvoiceLineRelatedToProject By enabling this option, you will display the purchase invoice lines attached to a business project, in the "Related elements" tab of a business project.
20 axelor-business-project AppBusinessProject app-business-project-config-form showSaleInvoiceLineRelatedToProject By enabling this option, you will display the sale invoice lines attached to a business project, in the "Related elements" tab of a business project.
21 axelor-business-project AppBusinessProject app-business-project-config-form enableToInvoiceTimesheet This option allows invoicing of timesheets in business projects.
22 axelor-business-project AppBusinessProject app-business-project-config-form enableToInvoiceExpense This option allows invoicing of expenses in business projects.

View File

@ -0,0 +1,22 @@
"module";"object";"view";"field";"help"
"axelor-business-project";"SaleOrder";"sale-order-form";"manualUnblock";"Si un client est bloqué, vous pouvez si vous en avez les droits le débloquer manuellement en cliquant sur cette case."
"axelor-business-project";"SaleOrder";"sale-order-form";"saleOrderSeq";"Numéro de référence interne de la commande, celui-ci est généré lors de la première sauvegarde du la commande. "
"axelor-business-project";"SaleOrder";"sale-order-form";"priceList";"Permet d'associer une liste de prix à utiliser spécifiquement pour cette commande. Ce champ est rempli automatiquement si une liste de prix est rattachée au tiers. "
"axelor-business-project";"SaleOrder";"sale-order-form";"project";"Permet de sélectionner un projet auquel rattacher la commande. Cette fonction liée à la gestion par affaire permettra de facturer (lors de la facturation de l'affaire) la commande ainsi que d'autres éléments."
"axelor-business-project";"SaleOrder";"sale-order-form";"expectedRealisationDate";"Permet de renseigner une date estimée de paiment de la facture qui sera générée à partir de la commande. "
"axelor-business-project";"SaleOrder";"sale-order-form";"hideDiscount";"Case à cocher permettant de ne pas faire apparaitre les informations détaillées des remises sur les impressions des devis/commandes."
"axelor-business-project";"SaleOrder";"sale-order-template-form";"createOrder";"Bouton permettant de générer un nouveau devis client à l'état brouillon à partir du modèle sélectionné. "
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"generateProjectOrder";"Cette option permet va permettre de sélectionner un projet sur une commande dans le cadre de la facturation à l'affaire. La commande sera rattachée à une affaire, sur laquelle vous pourrez facturer les lignes de commande."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"automaticProject";"Si cette option est activée, un projet sera automatiquement généré à chaque confirmation de commande client."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"projectSaleOrderLines";"Cette option permet d'activer un onglet concernant les projets/affaires dans les lignes de commandes clients, qui va permettre de sélectionner une affaire et d'indiquer si la ligne de commande doit être facturée dans l'affaire. Il s'agit donc d'une option indispensable pour facturer des lignes de commandes dans une affaire."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"projectPurchaseOrderLines";"Cette option permet d'activer un onglet concernant les projets/affaires dans les lignes de commandes fournisseurs, qui va permettre de sélectionner une affaire et d'indiquer si la ligne de commande doit être facturée dans l'affaire. Il s'agit donc d'une option indispensable pour facturer des lignes de commandes dans une affaire."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"projectInvoiceLines";"Cette option permet d'activer un onglet concernant les projets/affaires dans les lignes de factures, qui va permettre de rattacher les factures aux affaires."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"productInvoicingProject";"Permet de définir un produit de facturation par défaut sur les affaires, quand celles-ci sont facturées au forfait."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showPurchaseOrderLineRelatedToProject";"En activant cette option, vous afficherez les lignes de commandes fournisseurs rattachées à une affaire, dans l'onglet ""Eléments rattachés"" d'une affaire."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showSaleOrderLineRelatedToProject";"En activant cette option, vous afficherez les lignes de commandes clients rattachées à une affaire, dans l'onglet ""Eléments rattachés"" d'une affaire."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showProductionOrderRelatedToProject";"En activant cette option, vous afficherez les ordres de production rattachés à une affaire, dans l'onglet ""Eléments rattachés"" d'une affaire."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showExpenseLineRelatedToProject";"En activant cette option, vous afficherez les notes de frais rattachées à une affaire, dans l'onglet ""Eléments rattachés"" d'une affaire."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showPurchaseInvoiceLineRelatedToProject";"En activant cette option, vous afficherez les lignes de factures fournisseurs rattachées à une affaire, dans l'onglet ""Eléments rattachés"" d'une affaire."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"showSaleInvoiceLineRelatedToProject";"En activant cette option, vous afficherez les lignes de factures clients rattachées à une affaire, dans l'onglet ""Eléments rattachés"" d'une affaire."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"enableToInvoiceTimesheet";"Cette option permet d'autoriser la facturation des feuilles de temps dans les affaires."
"axelor-business-project";"AppBusinessProject";"app-business-project-config-form";"enableToInvoiceExpense";"Cette option permet d'autoriser la facturation des notes de frais dans les affaires."
1 module object view field help
2 axelor-business-project SaleOrder sale-order-form manualUnblock Si un client est bloqué, vous pouvez si vous en avez les droits le débloquer manuellement en cliquant sur cette case.
3 axelor-business-project SaleOrder sale-order-form saleOrderSeq Numéro de référence interne de la commande, celui-ci est généré lors de la première sauvegarde du la commande.
4 axelor-business-project SaleOrder sale-order-form priceList Permet d'associer une liste de prix à utiliser spécifiquement pour cette commande. Ce champ est rempli automatiquement si une liste de prix est rattachée au tiers.
5 axelor-business-project SaleOrder sale-order-form project Permet de sélectionner un projet auquel rattacher la commande. Cette fonction liée à la gestion par affaire permettra de facturer (lors de la facturation de l'affaire) la commande ainsi que d'autres éléments.
6 axelor-business-project SaleOrder sale-order-form expectedRealisationDate Permet de renseigner une date estimée de paiment de la facture qui sera générée à partir de la commande.
7 axelor-business-project SaleOrder sale-order-form hideDiscount Case à cocher permettant de ne pas faire apparaitre les informations détaillées des remises sur les impressions des devis/commandes.
8 axelor-business-project SaleOrder sale-order-template-form createOrder Bouton permettant de générer un nouveau devis client à l'état brouillon à partir du modèle sélectionné.
9 axelor-business-project AppBusinessProject app-business-project-config-form generateProjectOrder Cette option permet va permettre de sélectionner un projet sur une commande dans le cadre de la facturation à l'affaire. La commande sera rattachée à une affaire, sur laquelle vous pourrez facturer les lignes de commande.
10 axelor-business-project AppBusinessProject app-business-project-config-form automaticProject Si cette option est activée, un projet sera automatiquement généré à chaque confirmation de commande client.
11 axelor-business-project AppBusinessProject app-business-project-config-form projectSaleOrderLines Cette option permet d'activer un onglet concernant les projets/affaires dans les lignes de commandes clients, qui va permettre de sélectionner une affaire et d'indiquer si la ligne de commande doit être facturée dans l'affaire. Il s'agit donc d'une option indispensable pour facturer des lignes de commandes dans une affaire.
12 axelor-business-project AppBusinessProject app-business-project-config-form projectPurchaseOrderLines Cette option permet d'activer un onglet concernant les projets/affaires dans les lignes de commandes fournisseurs, qui va permettre de sélectionner une affaire et d'indiquer si la ligne de commande doit être facturée dans l'affaire. Il s'agit donc d'une option indispensable pour facturer des lignes de commandes dans une affaire.
13 axelor-business-project AppBusinessProject app-business-project-config-form projectInvoiceLines Cette option permet d'activer un onglet concernant les projets/affaires dans les lignes de factures, qui va permettre de rattacher les factures aux affaires.
14 axelor-business-project AppBusinessProject app-business-project-config-form productInvoicingProject Permet de définir un produit de facturation par défaut sur les affaires, quand celles-ci sont facturées au forfait.
15 axelor-business-project AppBusinessProject app-business-project-config-form showPurchaseOrderLineRelatedToProject En activant cette option, vous afficherez les lignes de commandes fournisseurs rattachées à une affaire, dans l'onglet "Eléments rattachés" d'une affaire.
16 axelor-business-project AppBusinessProject app-business-project-config-form showSaleOrderLineRelatedToProject En activant cette option, vous afficherez les lignes de commandes clients rattachées à une affaire, dans l'onglet "Eléments rattachés" d'une affaire.
17 axelor-business-project AppBusinessProject app-business-project-config-form showProductionOrderRelatedToProject En activant cette option, vous afficherez les ordres de production rattachés à une affaire, dans l'onglet "Eléments rattachés" d'une affaire.
18 axelor-business-project AppBusinessProject app-business-project-config-form showExpenseLineRelatedToProject En activant cette option, vous afficherez les notes de frais rattachées à une affaire, dans l'onglet "Eléments rattachés" d'une affaire.
19 axelor-business-project AppBusinessProject app-business-project-config-form showPurchaseInvoiceLineRelatedToProject En activant cette option, vous afficherez les lignes de factures fournisseurs rattachées à une affaire, dans l'onglet "Eléments rattachés" d'une affaire.
20 axelor-business-project AppBusinessProject app-business-project-config-form showSaleInvoiceLineRelatedToProject En activant cette option, vous afficherez les lignes de factures clients rattachées à une affaire, dans l'onglet "Eléments rattachés" d'une affaire.
21 axelor-business-project AppBusinessProject app-business-project-config-form enableToInvoiceTimesheet Cette option permet d'autoriser la facturation des feuilles de temps dans les affaires.
22 axelor-business-project AppBusinessProject app-business-project-config-form enableToInvoiceExpense Cette option permet d'autoriser la facturation des notes de frais dans les affaires.

View File

@ -0,0 +1,10 @@
"name";"title";"type";"model";"modelField";"targetModel";"sequence";"onClick";"gridView";"formView";"widgetAttrs";"showIf"
"updatedTaskSet";"Updated tasks";"many-to-many";"com.axelor.apps.base.db.Batch";"attrs";"com.axelor.team.db.TeamTask";0;;"business-project-team-task-grid";"team-task-form";"{""colSpan"": ""12""}";"$record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1"
"taskSpacer";;"Spacer";"com.axelor.apps.base.db.Batch";"attrs";;1;;;;"{""colSpan"": ""12""}";"$record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1"
"showUpdatedTaskBtn";"Show updated tasks";"Button";"com.axelor.apps.base.db.Batch";"attrs";;2;"action-project-invoicing-assistant-batch-method-show-task,close";;;"{""colSpan"": ""5""}";"$record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1"
"updatedTimesheetLineSet";"Updated timesheet lines";"many-to-many";"com.axelor.apps.base.db.Batch";"attrs";"com.axelor.apps.hr.db.TimesheetLine";3;;"timesheet-line-project-grid";"timesheet-line-project-form";"{""colSpan"": ""12""}";"$record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1"
"timesheetLineSpacer";;"Spacer";"com.axelor.apps.base.db.Batch";"attrs";;4;;;;"{""colSpan"": ""12""}";"$record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1"
"showUpdatedTimesheetLineBtn";"Show updated timesheet lines";"Button";"com.axelor.apps.base.db.Batch";"attrs";;5;"action-project-invoicing-assistant-batch-method-show-timesheet-line,close";;;"{""colSpan"": ""5""}";"$record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1"
"generatedInvoicingProjectSet";"Generated invoicing projects";"many-to-many";"com.axelor.apps.base.db.Batch";"attrs";"com.axelor.apps.businessproject.db.InvoicingProject";6;;"invoicing-project-grid";"invoicing-project-form";"{""colSpan"": ""12""}";"$record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 2"
"invProjectSpacer";;"Spacer";"com.axelor.apps.base.db.Batch";"attrs";;7;;;;"{""colSpan"": ""12""}";"$record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 2"
"showGeneratedInvoicingProjectBtn";"Show generated invoicing projects";"Button";"com.axelor.apps.base.db.Batch";"attrs";;8;"action-project-invoicing-assistant-batch-method-show-inv-project,close";;;"{""colSpan"": ""5""}";"$record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 2"
1 name title type model modelField targetModel sequence onClick gridView formView widgetAttrs showIf
2 updatedTaskSet Updated tasks many-to-many com.axelor.apps.base.db.Batch attrs com.axelor.team.db.TeamTask 0 business-project-team-task-grid team-task-form {"colSpan": "12"} $record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1
3 taskSpacer Spacer com.axelor.apps.base.db.Batch attrs 1 {"colSpan": "12"} $record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1
4 showUpdatedTaskBtn Show updated tasks Button com.axelor.apps.base.db.Batch attrs 2 action-project-invoicing-assistant-batch-method-show-task,close {"colSpan": "5"} $record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1
5 updatedTimesheetLineSet Updated timesheet lines many-to-many com.axelor.apps.base.db.Batch attrs com.axelor.apps.hr.db.TimesheetLine 3 timesheet-line-project-grid timesheet-line-project-form {"colSpan": "12"} $record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1
6 timesheetLineSpacer Spacer com.axelor.apps.base.db.Batch attrs 4 {"colSpan": "12"} $record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1
7 showUpdatedTimesheetLineBtn Show updated timesheet lines Button com.axelor.apps.base.db.Batch attrs 5 action-project-invoicing-assistant-batch-method-show-timesheet-line,close {"colSpan": "5"} $record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 1
8 generatedInvoicingProjectSet Generated invoicing projects many-to-many com.axelor.apps.base.db.Batch attrs com.axelor.apps.businessproject.db.InvoicingProject 6 invoicing-project-grid invoicing-project-form {"colSpan": "12"} $record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 2
9 invProjectSpacer Spacer com.axelor.apps.base.db.Batch attrs 7 {"colSpan": "12"} $record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 2
10 showGeneratedInvoicingProjectBtn Show generated invoicing projects Button com.axelor.apps.base.db.Batch attrs 8 action-project-invoicing-assistant-batch-method-show-inv-project,close {"colSpan": "5"} $record.projectInvoicingAssistantBatch != null && $record.projectInvoicingAssistantBatch.actionSelect == 2

View File

@ -0,0 +1,5 @@
"name";"roles.name"
"business-project-root";"Admin"
"business-project-folder";"Admin"
"business-project-all";"Admin"
"invoicing-project-all";"Admin"
1 name roles.name
2 business-project-root Admin
3 business-project-folder Admin
4 business-project-all Admin
5 invoicing-project-all Admin

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<csv-inputs xmlns="http://axelor.com/xml/ns/data-import"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/data-import http://axelor.com/xml/ns/data-import/data-import_5.2.xsd">
<input file="base_appBusinessProject.csv" separator=";" type="com.axelor.apps.base.db.AppBusinessProject" search="self.code = :code" update="true" />
<input file="account_accountConfig.csv" separator=";" type="com.axelor.apps.account.db.AccountConfig" search="self.importId = :importId" update="true"/>
</csv-inputs>

View File

@ -0,0 +1,2 @@
"importId";"displayTimesheetOnPrinting";"displayExpenseOnPrinting"
1;true;true
1 importId displayTimesheetOnPrinting displayExpenseOnPrinting
2 1 true true

View File

@ -0,0 +1,2 @@
"code";"generateProjectOrder";"projectSaleOrderLines";"projectPurchaseOrderLines";"projectInvoiceLines";"productInvoicingProject.importId";"showPurchaseOrderLineRelatedToProject";"showSaleOrderLineRelatedToProject";"showExpenseLineRelatedToProject"
"business-project";"true";"true";"true";"true";400;"true";"true";"true"
1 code generateProjectOrder projectSaleOrderLines projectPurchaseOrderLines projectInvoiceLines productInvoicingProject.importId showPurchaseOrderLineRelatedToProject showSaleOrderLineRelatedToProject showExpenseLineRelatedToProject
2 business-project true true true true 400 true true true

View File

@ -0,0 +1,2 @@
"importId";"displayTimesheetOnPrinting";"displayExpenseOnPrinting"
1;true;true
1 importId displayTimesheetOnPrinting displayExpenseOnPrinting
2 1 true true

View File

@ -0,0 +1,2 @@
"code";"generateProjectOrder";"projectSaleOrderLines";"projectPurchaseOrderLines";"projectInvoiceLines";"productInvoicingProject.importId";"showPurchaseOrderLineRelatedToProject";"showSaleOrderLineRelatedToProject";"showExpenseLineRelatedToProject"
"business-project";"true";"true";"true";"true";400;"true";"true";"true"
1 code generateProjectOrder projectSaleOrderLines projectPurchaseOrderLines projectInvoiceLines productInvoicingProject.importId showPurchaseOrderLineRelatedToProject showSaleOrderLineRelatedToProject showExpenseLineRelatedToProject
2 business-project true true true true 400 true true true

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="account" package="com.axelor.apps.account.db"/>
<entity name="AccountConfig" lang="java" cacheable="true">
<boolean name="displayTimesheetOnPrinting" title="Display timesheet lines on printing"/>
<boolean name="displayExpenseOnPrinting" title="Display expense lines on printing"/>
<track>
<field name="displayTimesheetOnPrinting" on="UPDATE"/>
<field name="displayExpenseOnPrinting" on="UPDATE"/>
</track>
</entity>
</domain-models>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="account" package="com.axelor.apps.account.db"/>
<entity name="AnalyticMoveLine" lang="java">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Project"/>
</entity>
</domain-models>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="account" package="com.axelor.apps.account.db"/>
<entity name="AnalyticMoveLine" lang="java">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Business project"/>
</entity>
</domain-models>

View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="base" package="com.axelor.apps.base.db"/>
<entity name="AppBusinessProject" lang="java" extends="App">
<many-to-one name="productInvoicingProject" ref="com.axelor.apps.base.db.Product" title="Default Invoicing Product for Projects"/>
<boolean name="showPurchaseOrderLineRelatedToProject" title="Show purchase order lines related to the project"/>
<boolean name="showSaleOrderLineRelatedToProject" title="Show sale order lines related to the project" />
<boolean name="showExpenseLineRelatedToProject" title="Show expense order lines related to the project" />
<boolean name="showProductionOrderRelatedToProject" title="Show production orders related to the project" />
<boolean name="showPurchaseInvoiceLineRelatedToProject" title="Show purchase invoice line related to the project"/>
<boolean name="showSaleInvoiceLineRelatedToProject" title="Show sale invoice line related to the project"/>
<boolean name="enableToInvoiceTimesheet" title="Enable to invoice timesheet" />
<boolean name="enableToInvoiceExpense" title="Enable to invoice expense" />
<boolean name="generateProjectOrder" title="Generate/Select Project for Order"/>
<boolean name="automaticProject" title="Automatic Project"/>
<integer name="generatedElementTypeSelect" title="Generated element type" default="3" selection="business.project.config.generated.element.type"/>
<boolean name="projectSaleOrderLines" title="Project in Sale order lines"/>
<boolean name="projectPurchaseOrderLines" title="Project in Purchase order lines"/>
<boolean name="projectInvoiceLines" title="Project in Invoice Lines"/>
<boolean name="enableTaskTemplatesByProduct" title="Enable task templates by product"/>
<string name="preTaskStatusSet" title="Status for invoice pre task tasks" selection="team.task.status"/>
<string name="postTaskStatusSet" title="Status for invoice post task tasks" selection="team.task.status"/>
<string name="exculdeTaskInvoicing" title="Exculde tasks for invoicing"/>
<track>
<field name="productInvoicingProject" on="UPDATE"/>
<field name="showPurchaseOrderLineRelatedToProject" on="UPDATE"/>
<field name="showSaleOrderLineRelatedToProject" on="UPDATE"/>
<field name="showExpenseLineRelatedToProject" on="UPDATE"/>
<field name="showProductionOrderRelatedToProject" on="UPDATE"/>
<field name="showPurchaseInvoiceLineRelatedToProject" on="UPDATE"/>
<field name="showSaleInvoiceLineRelatedToProject" on="UPDATE"/>
<field name="enableToInvoiceTimesheet" on="UPDATE"/>
<field name="enableToInvoiceExpense" on="UPDATE"/>
<field name="generateProjectOrder" on="UPDATE"/>
<field name="automaticProject" on="UPDATE"/>
<field name="generatedElementTypeSelect" on="UPDATE"/>
<field name="projectSaleOrderLines" on="UPDATE"/>
<field name="projectPurchaseOrderLines" on="UPDATE"/>
<field name="projectInvoiceLines" on="UPDATE"/>
<field name="enableTaskTemplatesByProduct" on="UPDATE"/>
</track>
</entity>
</domain-models>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="base" package="com.axelor.apps.base.db"/>
<entity name="Batch" lang="java" sequential="true">
<!-- NOT DISPLAY -->
<many-to-one name="projectInvoicingAssistantBatch" ref="com.axelor.apps.businessproject.db.ProjectInvoicingAssistantBatch"/>
</entity>
</domain-models>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="contract" package="com.axelor.apps.contract.db" />
<entity name="Contract" repository="abstract">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Project"/>
</entity>
</domain-models>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="account" package="com.axelor.apps.account.db"/>
<entity sequential="true" name="Invoice" lang="java">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Project" />
<boolean name="displayTimesheetOnPrinting" title="Display timesheet lines on printing"/>
<boolean name="displayExpenseOnPrinting" title="Display expense lines on printing"/>
</entity>
</domain-models>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="account" package="com.axelor.apps.account.db"/>
<entity name="InvoiceLine" lang="java">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Project" />
</entity>
</domain-models>

View File

@ -0,0 +1,39 @@
<?xml version="1.0" ?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="business-project" package="com.axelor.apps.businessproject.db"/>
<entity name="InvoicingProject" cacheable="true">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Business project"/>
<many-to-many name="logTimesSet" ref="com.axelor.apps.hr.db.TimesheetLine" title="Log Times" />
<many-to-many name="saleOrderLineSet" ref="com.axelor.apps.sale.db.SaleOrderLine" title="Sale order lines" />
<many-to-many name="purchaseOrderLineSet" ref="com.axelor.apps.purchase.db.PurchaseOrderLine" title="Purchase order lines" />
<many-to-many name="expenseLineSet" ref="com.axelor.apps.hr.db.ExpenseLine" title="Expense Lines" />
<many-to-many name="projectSet" ref="com.axelor.apps.project.db.Project" title="Project" />
<many-to-many name="teamTaskSet" ref="com.axelor.team.db.TeamTask" title="Tasks" />
<integer name="logTimesSetPrioritySelect" selection="invoicing.project.priority.select" title="Log Times Priority" default="3"/>
<integer name="saleOrderLineSetPrioritySelect" selection="invoicing.project.priority.select" title="Sale order lines Priority" default="1"/>
<integer name="purchaseOrderLineSetPrioritySelect" selection="invoicing.project.priority.select" title="Purchase order lines Priority" default="2"/>
<integer name="expenseLineSetPrioritySelect" selection="invoicing.project.priority.select" title="Expense Lines Priority" default="4"/>
<integer name="projectSetPrioritySelect" selection="invoicing.project.priority.select" title="Project Priority" default="5"/>
<integer name="teamTaskSetPrioritySelect" selection="invoicing.project.priority.select" title="Task Priority" default="6"/>
<many-to-one name="invoice" ref="com.axelor.apps.account.db.Invoice" title="Invoice generated" />
<date name="deadlineDate" title="Deadline"/>
<string name="comments" title="Comments" large="true" />
<boolean name="attachAnnexToInvoice" title="Attach the Annex to the invoice"/>
<integer name="statusSelect" title="Status" selection="business.project.invoicing.project.status.select" default="1"/>
<extra-code>
// STATUS SELECT
public static final int STATUS_DRAFT = 1;
public static final int STATUS_GENERATED = 2;
public static final int STATUS_VALIDATED = 3;
public static final int STATUS_VENTILATED = 4;
public static final int STATUS_CANCELED = 5;
</extra-code>
</entity>
</domain-models>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" ?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="business-project" package="com.axelor.apps.businessproject.db"/>
<entity name="ManualElement" cacheable="true">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Project"/>
<string name="title" title="Title" required="true"/>
<date name="date" column="date_val" title="Date"/>
<decimal name="turnover" title="Turnover W.T."/>
<decimal name="cost" title="Cost W.T."/>
<many-to-one name="currency" ref="com.axelor.apps.base.db.Currency" title="Currency"/>
<integer name="typeSelect" title="Type" selection="business.project.manual.element.type.select" default="1"/>
<string name="comments" title="Comments" large="true"/>
</entity>
</domain-models>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="base" package="com.axelor.apps.base.db"/>
<entity name="Partner" lang="java">
<integer name="chargeBackPurchaseSelect" title="Charging Back Purchases Type" selection="business.project.charging.back.purchases.select"/>
<decimal name="chargeBackPurchase" title="% Charging Back Purhcases" default="100"/>
<extra-code><![CDATA[
// TYPE SELECT
public static final int CHARGING_BACK_TYPE_IDENTICALLY = 1;
public static final int CHARGING_BACK_TYPE_PRICE_LIST = 2;
public static final int CHARGING_BACK_TYPE_PERCENTAGE = 3;
]]></extra-code>
</entity>
</domain-models>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="base" package="com.axelor.apps.base.db"/>
<entity name="Product">
<many-to-many name="taskTemplateSet" ref="com.axelor.apps.project.db.TaskTemplate" title="Task templates"/>
</entity>
</domain-models>

View File

@ -0,0 +1,75 @@
<?xml version="1.0" ?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="project" package="com.axelor.apps.project.db"/>
<entity name="Project" cacheable="true">
<many-to-one name="currency" ref="com.axelor.apps.base.db.Currency" title="Currency" massUpdate="true"/>
<integer name="invoicingSequenceSelect" title="Invoicing sequence" selection="business.project.invoicing.sequence.select"/>
<string name="invoicingComment" title="Invoicing comment" large="true" />
<decimal name="totalSaleOrdersFinalized" title="Finalized Orders Total" readonly="true"/>
<decimal name="totalSaleOrdersConfirmed" title="Confirmed Orders Total" readonly="true"/>
<decimal name="totalSaleOrdersInvoiced" title="Invoiced Orders Total" readonly="true"/>
<many-to-one name="priceList" ref="com.axelor.apps.base.db.PriceList" title="Price list"/>
<decimal name="totalPurchaseOrdersFinalized" title="Finalized Orders Total" readonly="true"/>
<decimal name="totalPurchaseOrdersConfirmed" title="Confirmed Orders Total" readonly="true"/>
<decimal name="totalPurchaseOrdersInvoiced" title="Invoiced Orders Total" readonly="true"/>
<decimal name="totalTimesPlanned" title="Planned Times Total" readonly="true"/>
<decimal name="totalTimesRealised" title="Realised Times Total" readonly="true"/>
<decimal name="totalExpenses" title="ExpensesTotal" readonly="true"/>
<decimal name="totalEstimatedCosts" title="Estimated Costs Total" readonly="true"/>
<decimal name="totalRealCosts" title="Real Costs Total" readonly="true"/>
<decimal name="totalProducedTurnOver" title="Produced Turnover" readonly="true"/>
<decimal name="estimatedMargin" title="Estimated Margin" readonly="true"/>
<decimal name="realTimesMargin" title="Real Margin (Time)" readonly="true"/>
<decimal name="realInvoicingMargin" title="Real Margin (Invoicing)" readonly="true"/>
<one-to-many name="manualElementList" ref="com.axelor.apps.businessproject.db.ManualElement" title="Manual elements" mappedBy="project"/>
<boolean name="invoiced" readonly="true"/>
<string name="unitOnPrinting" selection="hr.time.logging.preference.select" title="Invoicing unit"/>
<one-to-many name="purchaseOrderLineList" ref="com.axelor.apps.purchase.db.PurchaseOrderLine" title="Purchase order lines" mappedBy="project" orphanRemoval="false"/>
<one-to-many name="saleOrderLineList" ref="com.axelor.apps.sale.db.SaleOrderLine" title="Sale order lines" mappedBy="project" orphanRemoval="false"/>
<one-to-many name="expensesLineList" ref="com.axelor.apps.hr.db.ExpenseLine" title="Expense lines" mappedBy="project" orphanRemoval="false"/>
<one-to-many name="invoiceLineList" ref="com.axelor.apps.account.db.InvoiceLine" title="Invoice lines" mappedBy="project" orphanRemoval="false"/>
<boolean name="isBusinessProject" title="Business project" />
<boolean name="toInvoice" title="To invoice"/>
<boolean name="isInvoicingTimesheet" title="Invoicing timesheet"/>
<boolean name="isInvoicingExpenses" title="Invoicing Expenses"/>
<boolean name="isInvoicingPurchases" title="Invoicing Purchases"/>
<many-to-one name="customerAddress" title="Address" ref="com.axelor.apps.base.db.Address"/>
<extra-code><![CDATA[
// TYPE SELECT
public static final int INVOICING_SEQ_EMPTY = 0;
public static final int INVOICING_SEQ_INVOICE_PRE_TASK = 1;
public static final int INVOICING_SEQ_INVOICE_POST_TASK = 2;
public static final int TASK_PER_LINE_ALONE = 1;
public static final int TASK_PER_LINE_PHASE = 2;
public static final int TASK_PER_LINE_TASK = 3;
]]></extra-code>
</entity>
<enum name="ProjectGeneratorType">
<item name="PROJECT_ALONE" title="Project alone"/>
<item name="PHASE_BY_LINE" title="Phase by line"/>
<item name="TASK_BY_LINE" title="Task by line"/>
<item name="TASK_TEMPLATE" title="Tasks by product"/>
</enum>
</domain-models>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" ?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="business-project" package="com.axelor.apps.businessproject.db"/>
<entity name="ProjectInvoicingAssistantBatch" cacheable="true">
<!-- HEADER -->
<string name="code" title="Code" namecolumn="true" unique="true"/>
<integer name="actionSelect" title="Action" required="true" selection="project.invoicing.assistant.batch.action.select"/>
<many-to-one name="company" ref="com.axelor.apps.base.db.Company" title="Company" />
<!-- OTHERS INFORMATIONS -->
<string name="description" title="Description" large="true" />
<one-to-many name="batchList" ref="com.axelor.apps.base.db.Batch" mappedBy="projectInvoicingAssistantBatch" title="Batches" />
<extra-code><![CDATA[
// ACTION TYPE
public static final int ACTION_UPDATE_TASKS = 1;
public static final int ACTION_GENERATE_INVOICING_PROJECT = 2;
]]></extra-code>
</entity>
</domain-models>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" ?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="project" package="com.axelor.apps.project.db"/>
<entity name="ProjectTemplate">
<boolean name="isInvoicingExpenses" title="Invoicing Expenses"/>
<boolean name="isInvoicingPurchases" title="Invoicing Purchases"/>
<integer name="invoicingTypeSelect" selection="project.invoicing.type.select" title="Invoicing Type"/>
<string name="invoicingComment" title="Invoicing comment" large="true"/>
</entity>
</domain-models>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="purchase" package="com.axelor.apps.purchase.db"/>
<entity name="PurchaseOrder" lang="java">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Project" />
</entity>
</domain-models>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="purchase" package="com.axelor.apps.purchase.db"/>
<entity name="PurchaseOrderLine" lang="java">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Project"/>
<boolean name="toInvoice" title="To invoice with project"/>
</entity>
</domain-models>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="purchase" package="com.axelor.apps.purchase.db"/>
<entity name="PurchaseRequest" lang="java">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Project" />
</entity>
</domain-models>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<domain-models xmlns="http://axelor.com/xml/ns/domain-models"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://axelor.com/xml/ns/domain-models http://axelor.com/xml/ns/domain-models/domain-models_5.2.xsd">
<module name="sale" package="com.axelor.apps.sale.db"/>
<entity name="SaleOrder" lang="java">
<many-to-one name="project" ref="com.axelor.apps.project.db.Project" title="Project" />
<boolean name="toInvoiceViaTask" title="To invoice via task" default="false"/>
</entity>
</domain-models>

Some files were not shown because too many files have changed in this diff Show More