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

1
.dockerignore Normal file
View File

@ -0,0 +1 @@
./init-db

54
.gitignore vendored Normal file
View File

@ -0,0 +1,54 @@
# Gradle
build
.gradle
# Eclispe
bin
.project
.classpath
.settings
.metadata
# Intellij
out
.idea
*.iml
*.ipr
*.iws
atlassian-ide-plugin.xml
# NetBeans
.nbattrs
# virtual machine crash logs
hs_err_pid*
# Backup files
*.sw[nop]
*~
.#*
[#]*#
# dotenv or direnv
.env
.envrc
# Miscellaneous
*.log
.clover
.DS_Store
# Profiler and heap dumps
*.jps
*.hprof
/.nb-gradle/
# JavaScript
node_modules
src/main/resources/application.properties
src/main/resources/application.properties
src/main/resources/application.properties
init-db/bdd_sophal202506281027.sql
modules/axelor-open-suite/axelor-account/src/test/resources/META-INF/persistence.xml
modules/axelor-open-suite/axelor-supplychain/src/test/java/com/axelor/apps/supplychain/db/StockMove.java

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "axelor-open-suite"]
path = modules/axelor-open-suite
url = git@github.com:axelor/axelor-open-suite.git

49
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,49 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "java",
"name": "Test",
"request": "launch",
"mainClass": "com.axelor.apps.account.service.Test",
"projectName": "axelor-account"
},
{
"type": "java",
"name": "Previous",
"request": "launch",
"mainClass": "com.axelor.apps.production.service.Previous",
"projectName": "axelor-production"
},
{
"type": "java",
"name": "AccountingCutOffServiceImpl",
"request": "launch",
"mainClass": "com.axelor.apps.supplychain.service.AccountingCutOffServiceImpl",
"projectName": "axelor-supplychain"
},
{
"type": "java",
"name": "Test",
"request": "launch",
"mainClass": "com.axelor.apps.stock.service.Test",
"projectName": "axelor-stock"
},
{
"type": "java",
"name": "Current File",
"request": "launch",
"mainClass": "${file}"
},
{
"type": "java",
"name": "QAPortType_QAPortType_Client",
"request": "launch",
"mainClass": "com.qas.web_2005_02.QAPortType_QAPortType_Client",
"projectName": "axelor-tool"
}
]
}

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"java.compile.nullAnalysis.mode": "automatic",
"java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx8G -Xms100m -Xlog:disable",
"java.debug.settings.onBuildFailureProceed": true
}

265
CHANGELOG.md Normal file
View File

@ -0,0 +1,265 @@
# Changelog
## [5.2.1] - 2019-12-16
## Features
- ACCOUNTING REPORT: add new report, bank reconciliation statement.
## Improvements
- INVOICE: new mandatory labelling: Head office address.
- Company: Add tree view for companies.
- AdvancedExportLine: Add translation for field orderByType.
- PURCHASE REQUEST: add new columns in purchase request grid view.
- MOVE: changed position of reconciliation tag in move form.
- BANK STATEMENT: add caption under bank statement line grid in bank statement form in order to explain the colors are used in bank statement line grid.
- PRODUCT: update translation for "Service" and "Product".
- STOCK MOVE: empty reservation date time on duplicate stock move.
- STOCK MOVE: Update stock move's form view.
- SALE ORDER PRINTING: rename title "Sale order" to "Order Acknowledgement" of report on condition.
- MOVE: Improved messages when there is an exception on trying to remove an accounting move.
- Partner Form: change the french translation of "Create sale quotation".
- STOCK MOVE: empty to and from stock location set on company change.
- STOCK MOVE: hide reserved qty when it is a supplier arrival or a customer return.
- STOCK MOVE: rename title of stock-move-form buttons related to PFP.
- STOCK MOVE: update pfp tags on stock move form.
- Invoicing project: unit conversion for "Duration adjust for customer".
- ACCOUNTING REPORT: change the title of "General ledger 2" from the selection.
- TAX: Show type select in grid view.
- Sale order/quotation: fix tab title when generating a quotation from an opportunity.
## Bug Fixes
- ANALYTIC: analytic journal in analytic line is now required.
- REFUND: avoid blocking message when ventilating the invoice.
- MOVE: fix display of status tag in move form.
- Manuf Order: fix real quantity not updating when a new line in consumed products is created.
- INVOICE PAYMENT CANCELLATION: corrected error when boolean allow removal validate move in account configuration is true.
- INVOICE: stopped the creation of invoice payment when a reconciliation is made with accounts not used in partner balance.
- User: find user by email using partner email address.
- Invoice: fix exception during passed for payment validation.
- Resolve NPE on stockMoveLines while displaying archived records.
- StockMove: set readonly to/fromStockLocation if status != Draft.
- INVOICE: remove the possibility for the user to manually link a stockMove to an invoice.
- PURCHASE ORDER LINE: isFilterOnSupplier is always true by default and can be set to false manually.
- INVOICE: Fix error on merging two invoices.
- Invoice: fix payment button visibility issue.
- HR: update insert leave method for mobile app.
- INVOICE: Fix printing of unit price when invoiceLine type is title.
- MOVE LINE: fix amount paid display in move line form.
- STOCK: ProductWorth computation fixed in ABCAnalysis.
- BASE: ABC Analysis Line with qty and worth equal to 0 are now removed.
- Fix Issues on EBICS user and partner form.
- Purchase Order: fix view budgetDistributionListPanel of purchaseOrderLine.
- Weighted Average Price: Fix computation issue causing an error in wap price.
- STOCK MOVE: fix the problem of partially invoiced qty in invoicing wizard form.
- STOCK CORRECTION: fixed error when qty is negative by reversing toStockLocation and fromStockLocation of created stock move.
- MASS INVOICING STOCK MOVE: fix error when selecting stock move to invoice.
## [5.2.0] - 2019-11-29
## Features
- Migration to Axelor Open Platform 5.2.
- Axelor-Business-Support: Addition of new module and app 'axelor-business-support'.
- Employee: added DPAE.
- TeamTask: added Frequency to be able to repeat tasks on given points in time.
- Employee: added wizard to create a new employee.
- SaleOrder: added possibility to invoice via generated task.
- Project: add support for project version.
- Project: add new form to create announcement for a given project.
- New menu and form stock correction allowing to fix a quantity in stock.
- User Form: Provide step wise view to create a user.
- TeamTask: Complete rework of team task model and views.
- Project: Complete rework of project model and views.
- Base: Addition of new object 'MailingListMessage' along with views, parent menu and sub-menus.
- InvoicingProject: Added new report 'InvoicingProjectAnnex.rptdesign' and attach to object on generating invoice.
- HR: Add CSV export support for Employment Contracts from its view and HR batch.
- Quality: Major improvements in axelor-quality module.
- QUALITY CONTROL: New report to print.
- AppBase: Add new configuration allowing to disable multi company support.
- OPPORTUNITY: Create event from opportunity.
- PROJECT: Add new feature allowing to create a template for a project.
- Invoice & PurchaseOrder: Added a budget overview.
- Advanced Import: Add feature to import data with advanced configurations.
- BPM: More than one workflow support for a same object.
- Sale Order/Sale Invoice: allow to change customer in existing invoice or order.
- MESSAGE TEMPLATE: added the management of additional contexts (groovy evaluation) in order to allow the use of Json fields.
- FORECAST RECAP: Add support of printing report in 'xls' and 'ods' format.
- PERIOD: Add a new popup when closing period to allow user to check and validate move lines.
- Stock Move: Add support for partial invoicing.
- ABC ANALYSIS: Add support for printing report in 'xls' type.
- Business Project: Add 'Project invoicing assistant' batch to update tasks and generate invoicing projects.
- Project Folder: Add two printings to display all project elements linked to the folder.
- Distance travelled calculation of kilometric expense line with Open street map.
- Timesheet: add timesheet reporting.
- Stock: Add stock history view for a given product, company and stock location.
- Production: Provide menu for Machine Planning.
- Company: Add employee Phonebook.
- Base: Addition of fields 'height' and 'width' in Company to change logo's dimension in Reports.
- Add a payment validator in supplier invoices.
## Improvements
- SaleOrder/Partner: adding new fields for comments on invoices, sale orders, purchase orders and deliveries.
- Timesheet: assign Task to lines when generating from Realise Planning.
- Timesheet: mark timesheet line as to be invoiced while generating it from Realise Planning.
- TeamTask: Add button to enter spent time.
- LogisticalForm: if config enabled, send an email on first save.
- MANUF. APP: new config to hide cost sheet group.
- Purchase Request: Add the possibility to select purchase orders.
- Production: Addition of two dummy fields to calculate sum of planned and real duration of operation orders.
- MOVE: improve reversion process.
- SaleOrder: task by product and task by line invoicing.
- SALE ORDER: Update in 'Quotations template' working process and view.
- DataBackup: Add possibility to restore date fields from a given relative date.
- PURCHASE ORDER LINES/INVOICE LINES: New fields related to budget.
- WEEKLY PLANNING: Add a type and minor changes.
- BULK UNIT COST CALCULATION: new way to compute all unit costs using BOM. Allow to compute cost using BOM level sequence.
- MRP: Generate new sequence on save.
- DataBackup: update importId when its null with format IDDDMMYYHHMM.
- Generating supplier order from partner form.
- Mobile App: Add configuration for quality app on mobile app.
- INVOICE: new process to print.
- PERMISSIONS: Display dashlets for groups/roles/users using the permission in permission and meta permission form views.
- OPPORTUNITY: Rename "opportunity type" to "type of need".
- INVOICE: Change form view's organization to match the SaleOrder view.
- PARTNER: Add link to employee form.
- PRICE LIST: Add dashlets to display partner.
- MRP: add boolean to exclude product without proposal in the result dashlet.
- HR: TRAINING - Optimization of the menu by adding filters
- MRP: Group proposals per supplier
- HR: rework training and recruitment menus.
- Data import: in the import file, add the possibility to fill selects either by values, title or translated titles.
- Action Builder: Add feature to create templates using json models to send email.
- FORECAST RECAP: sequence feature added for ForeCastRecap.
- Advance data import: Add new config to check if new configuration is added on file and do import according to file.
- UNIT: allows to translate name and label.
- STOCK RULE: Add template on StockRule and StockConfig used for mail notifications.
- CONFORMITY CERTIFICATE: display external reference on printing.
- TIMESHEET: new config to display line numbers.
- Advanced Import: Add support of imported records removal.
- SALE ORDER: Recompute unit price when hideDiscount is true.
- OPPORTUNITY: Auto fill sale-order form and cancel linked sale orders on 'closed lost' status.
- OBJECT DATA CONFIG: UX improvements and translations and change in export type.
- ANALYTIC MOVE LINE: project field title changed and domain filter added.
- CONTRACT: Set invoice date with newly added options for invoicing moment.
- Inventory: Manage different type of inventory: yearly or cycle turning.
- Address: Street have now a dedicated object.
- SALE ORDER / PURCHASE ORDER / INVOICES: Lines panel height set to 30.
- MOVE: add the possibility to choose a date while generating reverse move.
- Contract: Add analytic information to contract lines.
- MESSAGE TEMPLATE: help to suggest use of separator between email addresses.
- PRODUCTION ORDER: user can define manuf order's planned end date while creating production order from product form.
- PARTNER: new HTML field on partner for proforma.
- Contract: added button to manually close contract if termination date was set in the future.
- ContractLine: hide `isConsumptionLine` if not activated in Contract config.
- Employee: Add a creation workflow and allow to automatically create or link a user.
- TimesheetLine: Add reference to TeamTask and add time to charge field.
- Timesheet: Change tab title.
- Studio: Allowing to export all data without selecting any app builder.
- Studio: Custom model editor - Added title property for model and removed required condition for AppBuilder.
- MENUS: new organisation in CRM and Sales modules.
- Mobile: Add new app setting for 'Task'.
- JobPosition: Cannot open a position when status in on hold.
- Purchase Order: remove IPurchaseOrder deprecated class.
- Event: Allowing to suppress unsynchronized events.
- Employee: Add birth department and city of birth in employee.
- Employment Contract: Set form width to large.
- Contract: partner/project filters improved.
- APP BUILDER: Remove JsonCreator object.
- ContractBatch: Set default bankDetails of partner to created invoice bankDetails.
- PRICE LIST: hide historized price lists in pop-up view.
- MARKETING: Precise domain for model in message template.
- Change titles for productFamily.
- CONTRACT: Set project on generated invoices.
- ACCOUNT MOVE REVERSE: Selected reverse move date must not be after the date of the day
- ACCOUNT MOVE REVERSE: add the possibility to choose to hide or not the move lines (origin and reverse) in bank reconciliation
- Change google-plus icon by google one.
- Sale Order Line: Replacing 'price' with 'priceDiscounted' in a Grid View along with PurchaseOrderLine and InvoiceLine
- SUPPLY CHAIN: delete boolean manageInvoicedAmountByLine.
- FUNCTION: new object function on Sales and CRM and new M2O on partner
- CITIZENSHIP: Add new object citizenship on base and new M2O in country and employee
- EMPLOYEE: Files management added domains and demo data
- Inventory: Added calendar-view
- change term "Description" to "Comment" in english and "Commentaire" in french
- WEEKLY PLANNING: Days can be reordered and created.
- PROJECT / REPORTINGS: Addition of new dashboard - "Planned charge".
- INVENTORY: adding ODS file format in report selection type.
- Quality Control: Set default printing setting and update translation.
- INVOICE: Configure BIRT to generate an Excel and a Word file
- KEYWORD: remove Keyword model.
- Advanced Import: trim data before import.
- ACCOUNTING: year and accountSet fields are set empty when company is changed.
- ACCOUNTING CONFIGURATION AND REPORTED BALANCE: add a new journal parameter in accounting configuration named reported balance journal and this new parameter defines the journal used in the reported balance move line creation.
- PARTNER: Checks the consistency of the address list of a partner.
- EXCEPTION: Removing deprecated interface IException.
- PORTAL CLIENT: Add config to choose the type of connection (from ABS or external).
- DEMO DATA: Rename field data.
- ACCOUNTING BATCH: alert when the closing annual accounts batch already ran.
- CLIENT PORTAL: update the client form view.
- USER: Mass generation of random passwords.
- Advance data import: Set sequence of filetab and removed temporary file at the end which is created during the process.
- ACCOUNTING REPORT: add ODS file formate in report export type.
- FORECAST RECAP: reset fields while creating duplicate record.
- PICKING ORDER: new comment field for picking order on partner.
- INVOICE: Add field 'language' to change report language in company.
- QUALITY CONTROL: Add send email option when status is finished.
- EMPLOYEE: add emergency contact relationship.
- INVOICE PAYMENT: additionnal informations
- ACCOUNT CONFIG: update demo data for account config and 'is print invoices in company language' boolean is now at true by default.
- Contract: change filter on project field.
- TEAMTASKS: Creation from Same Order.
- PROJECT: show sub-menu project list when project type is empty.
- Financial Report: calculate total costs (per line) in chart and totals.
- ACCOUNTING REPORT: add Analytic general ledger.
- TIMETABLE: reworked timetables to have them work based on percentage of the order rather than on a per product basis. So far only for sale orders. Purchases to come.
- HRconfig: moved fields 'Health service' and 'Health service address' to HR module.
- STOCKMOVE: update stock move form view.
- MetaScheduler: fix MetaScheduler form-view in axelor-base module.
- AccountingReport: set configuration to display opening accounting moves default value to true.
- SUPPLYCHAIN: auto-complete sale order when it has been completely invoiced.
- Accounting situation: added two fields to manage the credit insurance.
- BoM: added a menu showing personalized bills of materials.
## Bug Fixes
- Studio: Fix import app without image.
- Generation of Project/Phase from SaleOrder.
- Contract: Fix issue of not saving currentContractVersion fields in form view.
- ProductTaskTemplate: fix button display issue for edit and remove buttons on tree view.
- Employee: Fix issue of not saving each phase of creation process.
- Marketing: Fix error when trying to generate an event per target.
- Contract: Fix import error in data-init.
- BUSINESS PROJECT: Report printing Division by zero.
- UnitCostCalculation: Fixed the date format in the csv export name file.
- BONUS MGT: Fix formula variable error of human resource when computing amounts.
- INVOICE: Hide Due amount in report while printing "Original invoice / Updated copy".
- PurchaseOrder: Fill order date with sale order creation date when generating puchase order from sale order with interco.
- Purchase Order: Rename field 'priceDisplay' to 'displayPriceOnQuotationRequest'.
- INVOICE: Reduce font size of tax table in Invoice printing.
- PURCHASE ORDER PRINTING: display buyer email and phone as in sale order printing.
- ACCOUNT MOVE REVERSE: add translation.
- Transactionnal: correction and standardisation of rollback.
- CONFIGURATOR BOM: product, qty and unit are displayed in the grid-view.
- SALE ORDER LINE: fixed error when selecting a product.
- Studio: Fix readonly fields are enabled when imported an application.
- Studio: Fix error when click on wkf buttons.
- Studio: Fix export app.
- Advance Data Import: Fix indexOutOfBound Exception.
- Advanced Data Import: Specify truncated value to sampleLines for large string.
- REPORTED BALANCE: corrected abnormal amount in reported balance move lines if there was no partner associated to it.
- REPORTED BALANCE BATCH: the case where reported balance date on fiscal year is missing is now correctly managed.
- PURCHASE ORDER: fix issue in 'discountTypeSelect' of Purchase Order Line Form.
- Advanced Data import: fix issue of not generating info in log file when error occurred on import.
- Studio: fix m2o to metafile's widget property, display image,binarylink option.
- Advance data import: fix search issue, changed default import type of relational field to New and add import if condition for required Fields.
- Advance data import: Fix Data import error when there is same object in two different sheets.
- INVOICE: fix issue of invoice copy.
- TEAMTASK: Add fullname in demo data.
- Timesheet line: Duration label issue when created from mobile app.
- Purchase: Corrected translation of purchase not configured.
- SALEORDERLINE: Issue when Production module isn't installed.
- Invoice: replace field "irrecoverablestatusSelect" to "irrecoverableStatusSelect".
- SALE ORDER: fix error generating project without salemanUser.
- Advance Import: Resolve ArrayIndexOutOfBound exception.
- STOCK: Link back order with saleOrder or purchaseOrder.
- ADDRESS: when there is one address on partner it is treated as a default address.
- LEAVE REQUEST: Add error when leave reason has no unit.
- LEAVE REQUEST: Set duration value 0 if day planning of selected weekly planning is empty
[5.2.1]: https://github.com/axelor/axelor-open-suite/compare/v5.2.0...v5.2.1
[5.2.0]: https://github.com/axelor/axelor-open-suite/compare/v5.1.13...v5.2.0

95
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,95 @@
# Contributing Guide
Wed love for you to contribute to our source code and to make app even better.
While we try to keep requirements for contributing to a minimum,
there are a few guidelines wed like you to follow:
* [Contributor License Agreement](#contributor-license-agreement)
* [Reporting Issues](#reporting-issues)
* [Submitting](#submitting)
* [Code of Conduct](#code-of-conduct)
## Contributor License Agreement
By submitting code as an individual you agree to the [individual contributor license agreement][individual-cla].
By submitting code as an entity you agree to the [corporate contributor license agreement][corporate-cla].
## Reporting Issues
Before you submit your issue search the archive, maybe your question was already answered.
If your issue appears to be a bug, and hasn't been reported, open a new issue.
Help us to maximize the effort we can spend fixing issues and adding new features,
by not reporting duplicate issues. Providing the following information will increase
the chances of your issue being dealt with quickly:
* **Use Case** explain your use case
* **Overview of the issue** include stacktrace
* **Version** which version you are using?
* **Browsers and Operating System** is this a problem with all browsers?
* **Reproduce the Error** provide a patch against app to reproduce the error
* **Related Issues** has a similar issue been reported before?
* **Suggest a Fix** you can point to what might be causing the problem (line of code or commit)
Please make sure you dont post any sensitive information while reporting issues.
## Submitting
* [Fork](https://help.github.com/articles/fork-a-repo/) the repo.
* Code!
* Push your changes to the topic branch in your fork of the repository.
* Initiate a [pull request](http://help.github.com/send-pull-requests/)
* Update the issue, adding a comment including a link to the created pull request
## Code of Conduct
As contributors and maintainers of this project, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to
fairly and consistently applying these principles to every aspect of managing
this project. Project maintainers who do not follow or enforce the Code of
Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting a project maintainer at [conduct@axelor.com][mail]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. Maintainers are
obligated to maintain confidentiality with regard to the reporter of an
incident.
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]
[mail]: mailto:conduct@axelor.com
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/
[individual-cla]: http://axelor.com/cla/individuel-cla/
[corporate-cla]: http://axelor.com/cla/corporate-cla/

17
Dockerfile Normal file
View File

@ -0,0 +1,17 @@
FROM openjdk:8-jdk-alpine
WORKDIR /app
# Install dos2unix for line-ending fixes
RUN apk add --no-cache bash dos2unix
# Copy everything
COPY . .
# Fix line endings for gradlew
RUN dos2unix ./gradlew && chmod +x ./gradlew
# Clean and run the Gradle app
CMD ["./gradlew", "clean", "run", "--no-daemon"]

669
LICENSE Normal file
View File

@ -0,0 +1,669 @@
Axelor is published under the GNU AFFERO GENERAL PUBLIC LICENSE, Version 3
(AGPLv3), as included below. Some external libraries and contributions bundled
with Axelor may be published under other AGPLv3-compatible licenses. For
these, please refer to the relevant source files and/or license files, in the
source code tree.
**************************************************************************
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.

180
PyWhatKit_DB.txt Normal file
View File

@ -0,0 +1,180 @@
Date: 21/6/2024
Time: 19:13
Phone Number: +213554130569
Message: hello
--------------------
Date: 22/6/2024
Time: 21:33
Phone Number: +213554130569
Message: hello
--------------------
Date: 22/6/2024
Time: 21:36
Phone Number: +213542291107
Message: hello
--------------------
Date: 7/7/2024
Time: 0:8
Phone Number: +213541229487
Message: TEST MESSAGE
--------------------
Date: 7/7/2024
Time: 0:10
Phone Number: +213541229487
Message: TEST MESSAGE
--------------------
Date: 7/7/2024
Time: 0:16
Phone Number: +213541229487
Message: Votre TCO a ete accepté
--------------------
Date: 7/7/2024
Time: 0:19
Phone Number: +213541229487
Message: Votre TCO a ete acceptéhttp://localhost:8080/axelor-erp/#/ds/action-meta-actions/edit/3815
--------------------
Date: 7/7/2024
Time: 0:20
Phone Number: +213541229487
Message: Votre TCO a ete accepté http://localhost:8080/axelor-erp/#/ds/action-meta-actions/edit/3815
--------------------
Date: 7/7/2024
Time: 0:21
Phone Number: +213541229487
Message: Votre TCO a ete accepté http://localhost:8080/axelor-erp/#/ds/action-meta-actions/edit/3815
--------------------
Date: 7/7/2024
Time: 0:25
Phone Number: +213541229487
Message: Votre TCO a ete accepté http://localhost:8080/axelor-erp/#/ds/action-meta-actions/edit/23400
--------------------
Date: 7/7/2024
Time: 11:53
Phone Number: +213541229487
Message: hello https://dsi.sophal.dz//front/drh.MonDossierRH.php
--------------------
Date: 7/7/2024
Time: 11:54
Phone Number: +213541229487
Message: Votre TCO a ete accepté http://localhost:8080/axelor-erp/#/ds/action-meta-actions/edit/22874
--------------------
Date: 7/7/2024
Time: 11:56
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/22874
--------------------
Date: 7/7/2024
Time: 12:0
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/22873
--------------------
Date: 7/7/2024
Time: 12:1
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/21515
--------------------
Date: 7/7/2024
Time: 12:1
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/21515
--------------------
Date: 7/7/2024
Time: 12:1
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/21515
--------------------
Date: 7/7/2024
Time: 12:1
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/20428
--------------------
Date: 7/7/2024
Time: 12:2
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/21515
--------------------
Date: 7/7/2024
Time: 12:2
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/21514
--------------------
Date: 7/7/2024
Time: 13:27
Phone Number: +213541229487
Message: 40
--------------------
Date: 7/7/2024
Time: 13:31
Phone Number: +213541229487
Message: 52
--------------------
Date: 8/7/2024
Time: 13:12
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/22026 sc.root.purchase.orders.supplier.lines.requests/edit 22026
--------------------
Date: 8/7/2024
Time: 13:13
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/22027 sc.root.purchase.orders.supplier.lines.requests/edit 22027
--------------------
Date: 8/7/2024
Time: 13:23
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/22026 sc.root.purchase.orders.supplier.lines.requests/edit 22026
--------------------
Date: 8/7/2024
Time: 13:26
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/22024 sc.root.purchase.orders.supplier.lines.requests/edit 22024
--------------------
Date: 8/7/2024
Time: 13:31
Phone Number: +213541229487
Message: Votre TCO a ete accepté https://erp.sophal.net/sophal/#/ds/action-meta-actions/edit/23777 23777
--------------------
Date: 28/7/2024
Time: 11:30
Phone Number: +213541229487
Message: TEST MESSAGE sc.root.purchase.quotations/edit 22877
--------------------
Date: 28/7/2024
Time: 11:33
Phone Number: +213541229487
Message: TEST MESSAGE sc.root.purchase.quotations/edit 22878
--------------------
Date: 5/10/2024
Time: 22:53
Phone Number: +213541229487
Message: msg 123
--------------------
Date: 5/10/2024
Time: 23:5
Phone Number: +213541229487
Message: TCO ACCEPTER sc.root.purchase.orders.supplier.lines.requests/edit 25759
--------------------
Date: 5/10/2024
Time: 23:15
Phone Number: +213541229487
Message: TCO ACCEPTER http://localhost:8080/axelor-erp/#/ds/sc.root.purchase.orders.supplier.lines.requests/edit 25759
--------------------
Date: 5/10/2024
Time: 23:23
Phone Number: +213541229487
Message: TCO ACCEPTER [go to](http://localhost:8080/axelor-erp/#/ds/sc.root.purchase.orders.supplier.lines.requests/edit) 25759
--------------------
Date: 5/10/2024
Time: 23:25
Phone Number: +213541229487
Message: TCO ACCEPTER [go to](https://erp.sophal.net/#/ds/sc.root.purchase.orders.supplier.lines.requests/edit) 25759
--------------------
Date: 5/10/2024
Time: 23:27
Phone Number: +213541229487
Message: TCO ACCEPTER https://erp.sophal.net/#/ds/sc.root.purchase.orders.supplier.lines.requests/edit25759 25759
--------------------
Date: 5/10/2024
Time: 23:27
Phone Number: +213541229487
Message: TCO ACCEPTER https://erp.sophal.net/#/ds/sc.root.purchase.orders.supplier.lines.requests/edit/25759 25759
--------------------

29
README.md Normal file
View File

@ -0,0 +1,29 @@
Axelor Open Suite
================================
Axelor Open Suite reduces the complexity and improve responsiveness of business processes. Thanks to its modularity, you can start with few features and then activate other modules when needed.
Axelor Open Suite includes the following modules :
* Customer Relationship Management
* Sales management
* Financial and cost management
* Human Resource Management
* Project Management
* Inventory and Supply Chain Management
* Production Management
* Multi-company, multi-currency and multi-lingual
Axelor Open Suite is built on top of [Axelor Open Platform](https://github.com/axelor/axelor-open-platform)
Download
-------------------------
```bash
$ git clone git@github.com:axelor/open-suite-webapp.git
$ cd open-suite-webapp
$ git checkout master
$ git submodule init
$ git submodule update
$ git submodule foreach git checkout master
$ git submodule foreach git pull origin master
```

109
build.gradle Normal file
View File

@ -0,0 +1,109 @@
buildscript {
ext.repos = {
mavenCentral()
mavenLocal()
jcenter()
maven {
url 'https://plugins.gradle.org/m2/'
metadataSources {
artifact()
}
}
maven {
url 'https://repository.axelor.com/nexus/public/'
}
}
ext.openPlatformVersion = '5.2.2'
ext.appVersion = '5.2.1'
repositories repos
dependencies {
classpath "com.axelor:axelor-gradle:${openPlatformVersion}"
}
}
allprojects { repositories repos }
apply plugin: 'idea'
apply plugin: 'eclipse'
apply plugin: "com.axelor.app"
apply from: './gradle/style.gradle'
allprojects {
configurations {
runtime.exclude group:"org.eclipse.birt.runtime.3_7_1", module:"org.apache.commons.codec"
}
apply plugin: 'idea'
apply plugin: 'eclipse'
group = "com.axelor"
version = "${appVersion}"
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
subprojects {
group = "com.axelor.apps"
}
axelor {
title "Sophal"
description "Sophal Entreprise"
}
dependencies {
gradle.appModules.each { dir ->
compile project(":modules:$dir.name")
}
}
wrapper {
gradleVersion = "4.5.1"
}
task("dataImport", type: JavaExec) {
main = "com.axelor.apps.erp.Main"
classpath = sourceSets.main.runtimeClasspath
if(System.getProperty("exec.args") != null) {
args System.getProperty("exec.args").split()
}
}
task archiveReports(type: Zip) {
file("modules").traverse(type: groovy.io.FileType.DIRECTORIES, maxDepth: 1) { dir ->
if(new File(dir, "build.gradle").exists() && new File(dir, "/src/main/resources/reports").exists()) {
new File(dir, "/src/main/resources/reports/").listFiles().each { report ->
from report.getPath()
}
}
}
classifier 'reports'
includeEmptyDirs = false
destinationDir = file("$buildDir/libs")
}
war {
destinationDir = file("C:/apache-tomcat-8.5.0/webapps")
archiveName = "sophal2.war"
}
task stopTomcat(type: Exec) {
dependsOn stopTomcat
workingDir 'C:/apache-tomcat-8.5.0/bin'
commandLine 'cmd', '/c', 'shutdown.bat'
}
task startTomcat(type: Exec) {
dependsOn war
workingDir 'C:/apache-tomcat-8.5.0/bin'
commandLine 'cmd', '/c', 'startup.bat'
// commandLine 'cmd', '/c', 'start', '/b', 'startup.bat'
}
build.finalizedBy archiveReports

51
docker-compose.yml Normal file
View File

@ -0,0 +1,51 @@
version: '3.8'
services:
app:
build: .
depends_on:
- db
environment:
- DB_HOST=db
- DB_PORT=5432
- DB_NAME=bdd_sophal
- DB_USER=postgres
- DB_PASSWORD=root
ports:
- "8080:8080"
networks:
- backend
db:
image: postgres:9.6
environment:
POSTGRES_DB: bdd_sophal
POSTGRES_USER: postgres
POSTGRES_PASSWORD: root
POSTGRES_HOST_AUTH_METHOD: trust
ports:
- "5433:5432"
networks:
- backend
volumes:
- pgdata:/var/lib/postgresql/data
- ./init-db:/docker-entrypoint-initdb.d
pgadmin:
image: dpage/pgadmin4
environment:
PGADMIN_DEFAULT_EMAIL: admin@admin.com
PGADMIN_DEFAULT_PASSWORD: admin
ports:
- "5050:80"
depends_on:
- db
networks:
- backend
volumes:
pgdata:
networks:
backend:

22
gradle/style.gradle Normal file
View File

@ -0,0 +1,22 @@
buildscript {
repositories repos
dependencies {
classpath "com.diffplug.spotless:spotless-plugin-gradle:3.14.0"
}
}
apply plugin: com.diffplug.gradle.spotless.SpotlessPlugin
spotless {
java {
target fileTree(projectDir) {
include '**/*.java'
exclude '**/build/**'
}
googleJavaFormat()
}
}
task formatCode(dependsOn: ['licenseFormat', 'spotlessApply'])
build.dependsOn 'spotlessApply'

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-bin.zip

172
gradlew vendored Normal file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored Normal file
View File

@ -0,0 +1,84 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

16
modules/axelor-open-suite/.gitignore vendored Normal file
View File

@ -0,0 +1,16 @@
bin
build
.gradle
.project
.classpath
.settings
node_modules
application.min.*
*.sw[nop]
*~
.#*
[#]*#
.metadata/
.idea/
out/
*.iml

View File

@ -0,0 +1,265 @@
# Changelog
## [5.2.1] - 2019-12-16
## Features
- ACCOUNTING REPORT: add new report, bank reconciliation statement.
## Improvements
- INVOICE: new mandatory labelling: Head office address.
- Company: Add tree view for companies.
- AdvancedExportLine: Add translation for field orderByType.
- PURCHASE REQUEST: add new columns in purchase request grid view.
- MOVE: changed position of reconciliation tag in move form.
- BANK STATEMENT: add caption under bank statement line grid in bank statement form in order to explain the colors are used in bank statement line grid.
- PRODUCT: update translation for "Service" and "Product".
- STOCK MOVE: empty reservation date time on duplicate stock move.
- STOCK MOVE: Update stock move's form view.
- SALE ORDER PRINTING: rename title "Sale order" to "Order Acknowledgement" of report on condition.
- MOVE: Improved messages when there is an exception on trying to remove an accounting move.
- Partner Form: change the french translation of "Create sale quotation".
- STOCK MOVE: empty to and from stock location set on company change.
- STOCK MOVE: hide reserved qty when it is a supplier arrival or a customer return.
- STOCK MOVE: rename title of stock-move-form buttons related to PFP.
- STOCK MOVE: update pfp tags on stock move form.
- Invoicing project: unit conversion for "Duration adjust for customer".
- ACCOUNTING REPORT: change the title of "General ledger 2" from the selection.
- TAX: Show type select in grid view.
- Sale order/quotation: fix tab title when generating a quotation from an opportunity.
## Bug Fixes
- ANALYTIC: analytic journal in analytic line is now required.
- REFUND: avoid blocking message when ventilating the invoice.
- MOVE: fix display of status tag in move form.
- Manuf Order: fix real quantity not updating when a new line in consumed products is created.
- INVOICE PAYMENT CANCELLATION: corrected error when boolean allow removal validate move in account configuration is true.
- INVOICE: stopped the creation of invoice payment when a reconciliation is made with accounts not used in partner balance.
- User: find user by email using partner email address.
- Invoice: fix exception during passed for payment validation.
- Resolve NPE on stockMoveLines while displaying archived records.
- StockMove: set readonly to/fromStockLocation if status != Draft.
- INVOICE: remove the possibility for the user to manually link a stockMove to an invoice.
- PURCHASE ORDER LINE: isFilterOnSupplier is always true by default and can be set to false manually.
- INVOICE: Fix error on merging two invoices.
- Invoice: fix payment button visibility issue.
- HR: update insert leave method for mobile app.
- INVOICE: Fix printing of unit price when invoiceLine type is title.
- MOVE LINE: fix amount paid display in move line form.
- STOCK: ProductWorth computation fixed in ABCAnalysis.
- BASE: ABC Analysis Line with qty and worth equal to 0 are now removed.
- Fix Issues on EBICS user and partner form.
- Purchase Order: fix view budgetDistributionListPanel of purchaseOrderLine.
- Weighted Average Price: Fix computation issue causing an error in wap price.
- STOCK MOVE: fix the problem of partially invoiced qty in invoicing wizard form.
- STOCK CORRECTION: fixed error when qty is negative by reversing toStockLocation and fromStockLocation of created stock move.
- MASS INVOICING STOCK MOVE: fix error when selecting stock move to invoice.
## [5.2.0] - 2019-11-29
## Features
- Migration to Axelor Open Platform 5.2.
- Axelor-Business-Support: Addition of new module and app 'axelor-business-support'.
- Employee: added DPAE.
- TeamTask: added Frequency to be able to repeat tasks on given points in time.
- Employee: added wizard to create a new employee.
- SaleOrder: added possibility to invoice via generated task.
- Project: add support for project version.
- Project: add new form to create announcement for a given project.
- New menu and form stock correction allowing to fix a quantity in stock.
- User Form: Provide step wise view to create a user.
- TeamTask: Complete rework of team task model and views.
- Project: Complete rework of project model and views.
- Base: Addition of new object 'MailingListMessage' along with views, parent menu and sub-menus.
- InvoicingProject: Added new report 'InvoicingProjectAnnex.rptdesign' and attach to object on generating invoice.
- HR: Add CSV export support for Employment Contracts from its view and HR batch.
- Quality: Major improvements in axelor-quality module.
- QUALITY CONTROL: New report to print.
- AppBase: Add new configuration allowing to disable multi company support.
- OPPORTUNITY: Create event from opportunity.
- PROJECT: Add new feature allowing to create a template for a project.
- Invoice & PurchaseOrder: Added a budget overview.
- Advanced Import: Add feature to import data with advanced configurations.
- BPM: More than one workflow support for a same object.
- Sale Order/Sale Invoice: allow to change customer in existing invoice or order.
- MESSAGE TEMPLATE: added the management of additional contexts (groovy evaluation) in order to allow the use of Json fields.
- FORECAST RECAP: Add support of printing report in 'xls' and 'ods' format.
- PERIOD: Add a new popup when closing period to allow user to check and validate move lines.
- Stock Move: Add support for partial invoicing.
- ABC ANALYSIS: Add support for printing report in 'xls' type.
- Business Project: Add 'Project invoicing assistant' batch to update tasks and generate invoicing projects.
- Project Folder: Add two printings to display all project elements linked to the folder.
- Distance travelled calculation of kilometric expense line with Open street map.
- Timesheet: add timesheet reporting.
- Stock: Add stock history view for a given product, company and stock location.
- Production: Provide menu for Machine Planning.
- Company: Add employee Phonebook.
- Base: Addition of fields 'height' and 'width' in Company to change logo's dimension in Reports.
- Add a payment validator in supplier invoices.
## Improvements
- SaleOrder/Partner: adding new fields for comments on invoices, sale orders, purchase orders and deliveries.
- Timesheet: assign Task to lines when generating from Realise Planning.
- Timesheet: mark timesheet line as to be invoiced while generating it from Realise Planning.
- TeamTask: Add button to enter spent time.
- LogisticalForm: if config enabled, send an email on first save.
- MANUF. APP: new config to hide cost sheet group.
- Purchase Request: Add the possibility to select purchase orders.
- Production: Addition of two dummy fields to calculate sum of planned and real duration of operation orders.
- MOVE: improve reversion process.
- SaleOrder: task by product and task by line invoicing.
- SALE ORDER: Update in 'Quotations template' working process and view.
- DataBackup: Add possibility to restore date fields from a given relative date.
- PURCHASE ORDER LINES/INVOICE LINES: New fields related to budget.
- WEEKLY PLANNING: Add a type and minor changes.
- BULK UNIT COST CALCULATION: new way to compute all unit costs using BOM. Allow to compute cost using BOM level sequence.
- MRP: Generate new sequence on save.
- DataBackup: update importId when its null with format IDDDMMYYHHMM.
- Generating supplier order from partner form.
- Mobile App: Add configuration for quality app on mobile app.
- INVOICE: new process to print.
- PERMISSIONS: Display dashlets for groups/roles/users using the permission in permission and meta permission form views.
- OPPORTUNITY: Rename "opportunity type" to "type of need".
- INVOICE: Change form view's organization to match the SaleOrder view.
- PARTNER: Add link to employee form.
- PRICE LIST: Add dashlets to display partner.
- MRP: add boolean to exclude product without proposal in the result dashlet.
- HR: TRAINING - Optimization of the menu by adding filters
- MRP: Group proposals per supplier
- HR: rework training and recruitment menus.
- Data import: in the import file, add the possibility to fill selects either by values, title or translated titles.
- Action Builder: Add feature to create templates using json models to send email.
- FORECAST RECAP: sequence feature added for ForeCastRecap.
- Advance data import: Add new config to check if new configuration is added on file and do import according to file.
- UNIT: allows to translate name and label.
- STOCK RULE: Add template on StockRule and StockConfig used for mail notifications.
- CONFORMITY CERTIFICATE: display external reference on printing.
- TIMESHEET: new config to display line numbers.
- Advanced Import: Add support of imported records removal.
- SALE ORDER: Recompute unit price when hideDiscount is true.
- OPPORTUNITY: Auto fill sale-order form and cancel linked sale orders on 'closed lost' status.
- OBJECT DATA CONFIG: UX improvements and translations and change in export type.
- ANALYTIC MOVE LINE: project field title changed and domain filter added.
- CONTRACT: Set invoice date with newly added options for invoicing moment.
- Inventory: Manage different type of inventory: yearly or cycle turning.
- Address: Street have now a dedicated object.
- SALE ORDER / PURCHASE ORDER / INVOICES: Lines panel height set to 30.
- MOVE: add the possibility to choose a date while generating reverse move.
- Contract: Add analytic information to contract lines.
- MESSAGE TEMPLATE: help to suggest use of separator between email addresses.
- PRODUCTION ORDER: user can define manuf order's planned end date while creating production order from product form.
- PARTNER: new HTML field on partner for proforma.
- Contract: added button to manually close contract if termination date was set in the future.
- ContractLine: hide `isConsumptionLine` if not activated in Contract config.
- Employee: Add a creation workflow and allow to automatically create or link a user.
- TimesheetLine: Add reference to TeamTask and add time to charge field.
- Timesheet: Change tab title.
- Studio: Allowing to export all data without selecting any app builder.
- Studio: Custom model editor - Added title property for model and removed required condition for AppBuilder.
- MENUS: new organisation in CRM and Sales modules.
- Mobile: Add new app setting for 'Task'.
- JobPosition: Cannot open a position when status in on hold.
- Purchase Order: remove IPurchaseOrder deprecated class.
- Event: Allowing to suppress unsynchronized events.
- Employee: Add birth department and city of birth in employee.
- Employment Contract: Set form width to large.
- Contract: partner/project filters improved.
- APP BUILDER: Remove JsonCreator object.
- ContractBatch: Set default bankDetails of partner to created invoice bankDetails.
- PRICE LIST: hide historized price lists in pop-up view.
- MARKETING: Precise domain for model in message template.
- Change titles for productFamily.
- CONTRACT: Set project on generated invoices.
- ACCOUNT MOVE REVERSE: Selected reverse move date must not be after the date of the day
- ACCOUNT MOVE REVERSE: add the possibility to choose to hide or not the move lines (origin and reverse) in bank reconciliation
- Change google-plus icon by google one.
- Sale Order Line: Replacing 'price' with 'priceDiscounted' in a Grid View along with PurchaseOrderLine and InvoiceLine
- SUPPLY CHAIN: delete boolean manageInvoicedAmountByLine.
- FUNCTION: new object function on Sales and CRM and new M2O on partner
- CITIZENSHIP: Add new object citizenship on base and new M2O in country and employee
- EMPLOYEE: Files management added domains and demo data
- Inventory: Added calendar-view
- change term "Description" to "Comment" in english and "Commentaire" in french
- WEEKLY PLANNING: Days can be reordered and created.
- PROJECT / REPORTINGS: Addition of new dashboard - "Planned charge".
- INVENTORY: adding ODS file format in report selection type.
- Quality Control: Set default printing setting and update translation.
- INVOICE: Configure BIRT to generate an Excel and a Word file
- KEYWORD: remove Keyword model.
- Advanced Import: trim data before import.
- ACCOUNTING: year and accountSet fields are set empty when company is changed.
- ACCOUNTING CONFIGURATION AND REPORTED BALANCE: add a new journal parameter in accounting configuration named reported balance journal and this new parameter defines the journal used in the reported balance move line creation.
- PARTNER: Checks the consistency of the address list of a partner.
- EXCEPTION: Removing deprecated interface IException.
- PORTAL CLIENT: Add config to choose the type of connection (from ABS or external).
- DEMO DATA: Rename field data.
- ACCOUNTING BATCH: alert when the closing annual accounts batch already ran.
- CLIENT PORTAL: update the client form view.
- USER: Mass generation of random passwords.
- Advance data import: Set sequence of filetab and removed temporary file at the end which is created during the process.
- ACCOUNTING REPORT: add ODS file formate in report export type.
- FORECAST RECAP: reset fields while creating duplicate record.
- PICKING ORDER: new comment field for picking order on partner.
- INVOICE: Add field 'language' to change report language in company.
- QUALITY CONTROL: Add send email option when status is finished.
- EMPLOYEE: add emergency contact relationship.
- INVOICE PAYMENT: additionnal informations
- ACCOUNT CONFIG: update demo data for account config and 'is print invoices in company language' boolean is now at true by default.
- Contract: change filter on project field.
- TEAMTASKS: Creation from Same Order.
- PROJECT: show sub-menu project list when project type is empty.
- Financial Report: calculate total costs (per line) in chart and totals.
- ACCOUNTING REPORT: add Analytic general ledger.
- TIMETABLE: reworked timetables to have them work based on percentage of the order rather than on a per product basis. So far only for sale orders. Purchases to come.
- HRconfig: moved fields 'Health service' and 'Health service address' to HR module.
- STOCKMOVE: update stock move form view.
- MetaScheduler: fix MetaScheduler form-view in axelor-base module.
- AccountingReport: set configuration to display opening accounting moves default value to true.
- SUPPLYCHAIN: auto-complete sale order when it has been completely invoiced.
- Accounting situation: added two fields to manage the credit insurance.
- BoM: added a menu showing personalized bills of materials.
## Bug Fixes
- Studio: Fix import app without image.
- Generation of Project/Phase from SaleOrder.
- Contract: Fix issue of not saving currentContractVersion fields in form view.
- ProductTaskTemplate: fix button display issue for edit and remove buttons on tree view.
- Employee: Fix issue of not saving each phase of creation process.
- Marketing: Fix error when trying to generate an event per target.
- Contract: Fix import error in data-init.
- BUSINESS PROJECT: Report printing Division by zero.
- UnitCostCalculation: Fixed the date format in the csv export name file.
- BONUS MGT: Fix formula variable error of human resource when computing amounts.
- INVOICE: Hide Due amount in report while printing "Original invoice / Updated copy".
- PurchaseOrder: Fill order date with sale order creation date when generating puchase order from sale order with interco.
- Purchase Order: Rename field 'priceDisplay' to 'displayPriceOnQuotationRequest'.
- INVOICE: Reduce font size of tax table in Invoice printing.
- PURCHASE ORDER PRINTING: display buyer email and phone as in sale order printing.
- ACCOUNT MOVE REVERSE: add translation.
- Transactionnal: correction and standardisation of rollback.
- CONFIGURATOR BOM: product, qty and unit are displayed in the grid-view.
- SALE ORDER LINE: fixed error when selecting a product.
- Studio: Fix readonly fields are enabled when imported an application.
- Studio: Fix error when click on wkf buttons.
- Studio: Fix export app.
- Advance Data Import: Fix indexOutOfBound Exception.
- Advanced Data Import: Specify truncated value to sampleLines for large string.
- REPORTED BALANCE: corrected abnormal amount in reported balance move lines if there was no partner associated to it.
- REPORTED BALANCE BATCH: the case where reported balance date on fiscal year is missing is now correctly managed.
- PURCHASE ORDER: fix issue in 'discountTypeSelect' of Purchase Order Line Form.
- Advanced Data import: fix issue of not generating info in log file when error occurred on import.
- Studio: fix m2o to metafile's widget property, display image,binarylink option.
- Advance data import: fix search issue, changed default import type of relational field to New and add import if condition for required Fields.
- Advance data import: Fix Data import error when there is same object in two different sheets.
- INVOICE: fix issue of invoice copy.
- TEAMTASK: Add fullname in demo data.
- Timesheet line: Duration label issue when created from mobile app.
- Purchase: Corrected translation of purchase not configured.
- SALEORDERLINE: Issue when Production module isn't installed.
- Invoice: replace field "irrecoverablestatusSelect" to "irrecoverableStatusSelect".
- SALE ORDER: fix error generating project without salemanUser.
- Advance Import: Resolve ArrayIndexOutOfBound exception.
- STOCK: Link back order with saleOrder or purchaseOrder.
- ADDRESS: when there is one address on partner it is treated as a default address.
- LEAVE REQUEST: Add error when leave reason has no unit.
- LEAVE REQUEST: Set duration value 0 if day planning of selected weekly planning is empty
[5.2.1]: https://github.com/axelor/axelor-open-suite/compare/v5.2.0...v5.2.1
[5.2.0]: https://github.com/axelor/axelor-open-suite/compare/v5.1.13...v5.2.0

View File

@ -0,0 +1,95 @@
# Contributing Guide
Wed love for you to contribute to our source code and to make app even better.
While we try to keep requirements for contributing to a minimum,
there are a few guidelines wed like you to follow:
* [Contributor License Agreement](#contributor-license-agreement)
* [Reporting Issues](#reporting-issues)
* [Submitting](#submitting)
* [Code of Conduct](#code-of-conduct)
## Contributor License Agreement
By submitting code as an individual you agree to the [individual contributor license agreement][individual-cla].
By submitting code as an entity you agree to the [corporate contributor license agreement][corporate-cla].
## Reporting Issues
Before you submit your issue search the archive, maybe your question was already answered.
If your issue appears to be a bug, and hasn't been reported, open a new issue.
Help us to maximize the effort we can spend fixing issues and adding new features,
by not reporting duplicate issues. Providing the following information will increase
the chances of your issue being dealt with quickly:
* **Use Case** explain your use case
* **Overview of the issue** include stacktrace
* **Version** which version you are using?
* **Browsers and Operating System** is this a problem with all browsers?
* **Reproduce the Error** provide a patch against app to reproduce the error
* **Related Issues** has a similar issue been reported before?
* **Suggest a Fix** you can point to what might be causing the problem (line of code or commit)
Please make sure you dont post any sensitive information while reporting issues.
## Submitting
* [Fork](https://help.github.com/articles/fork-a-repo/) the repo.
* Code!
* Push your changes to the topic branch in your fork of the repository.
* Initiate a [pull request](http://help.github.com/send-pull-requests/)
* Update the issue, adding a comment including a link to the created pull request
## Code of Conduct
As contributors and maintainers of this project, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
By adopting this Code of Conduct, project maintainers commit themselves to
fairly and consistently applying these principles to every aspect of managing
this project. Project maintainers who do not follow or enforce the Code of
Conduct may be permanently removed from the project team.
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting a project maintainer at [conduct@axelor.com][mail]. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. Maintainers are
obligated to maintain confidentiality with regard to the reporter of an
incident.
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]
[mail]: mailto:conduct@axelor.com
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/
[individual-cla]: http://axelor.com/cla/individuel-cla/
[corporate-cla]: http://axelor.com/cla/corporate-cla/

View File

@ -0,0 +1,669 @@
Axelor is published under the GNU AFFERO GENERAL PUBLIC LICENSE, Version 3
(AGPLv3), as included below. Some external libraries and contributions bundled
with Axelor may be published under other AGPLv3-compatible licenses. For
these, please refer to the relevant source files and/or license files, in the
source code tree.
**************************************************************************
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
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/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<http://www.gnu.org/licenses/>.

View File

@ -0,0 +1,27 @@
Axelor Open Suite
================================
Axelor Open Suite reduces the complexity and improve responsiveness of business processes. Thanks to its modularity, you can start with few features and then activate other modules when needed.
Axelor Open Suite includes the following modules :
* Customer Relationship Management
* Sales management
* Financial and cost management
* Human Resource Management
* Project Management
* Inventory and Supply Chain Management
* Production Management
* Multi-company, multi-currency and multi-lingual
Axelor Open Suite is built on top of [Axelor Open Platform](https://github.com/axelor/axelor-open-platform)
Code Format
================================
Axelor follows Google Code Format.
Tools:
* Gradle Task: ./gradlew spotlessApply
* IDE plugin
* [Eclipse](https://github.com/google/google-java-format#eclipse)
* [IntelliJ](https://github.com/google/google-java-format#intellij)

View File

@ -0,0 +1,27 @@
apply plugin: "com.axelor.app-module"
apply from: "../version.gradle"
apply {
version = openSuiteVersion
}
axelor {
title "Axelor Account"
description "Axelor Account Module"
}
dependencies {
compile project(":modules:axelor-base")
compile project(":modules:axelor-purchase")
compile 'xalan:xalan:2.7.2'
testImplementation 'org.mockito:mockito-core:4.8.0' // Or latest version
compile group: 'jdom', name: 'jdom', version: '1.1'
compile group: 'org.apache.xmlbeans', name: 'xmlbeans', version: '2.5.0'
compile "org.bouncycastle:bcprov-jdk15on:1.62"
compile "org.bouncycastle:bcpkix-jdk15on:1.62"
}

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.account.db.repo;
import com.axelor.apps.account.db.Account;
import com.axelor.db.JPA;
import java.util.Set;
import javax.persistence.PersistenceException;
public class AccountAccountRepository extends AccountRepository {
@Override
public Account save(Account account) {
try {
if (account.getId() == null) {
return super.save(account);
}
if (account.getReconcileOk()) {
Set<Account> accountList = account.getCompatibleAccountSet();
if (accountList != null) {
for (Account acc : accountList) {
acc.setReconcileOk(true);
acc.addCompatibleAccountSetItem(account);
JPA.save(acc);
}
}
} else {
if (account.getCompatibleAccountSet() != null) {
for (Account acc : account.getCompatibleAccountSet()) {
acc.removeCompatibleAccountSetItem(account);
if (acc.getCompatibleAccountSet().size() == 0) {
acc.setReconcileOk(false);
}
JPA.save(acc);
}
account.getCompatibleAccountSet().clear();
}
}
return super.save(account);
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
}

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.account.db.repo;
import com.axelor.apps.account.db.AccountingBatch;
public class AccountingBatchAccountRepository extends AccountingBatchRepository {
@Override
public AccountingBatch copy(AccountingBatch entity, boolean deep) {
AccountingBatch copy = super.copy(entity, deep);
copy.setBatchList(null);
return copy;
}
}

View File

@ -0,0 +1,65 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.db.repo;
import com.axelor.apps.account.db.AccountingReport;
import com.axelor.apps.account.service.AccountingReportService;
import com.axelor.db.JPA;
import com.axelor.exception.service.TraceBackService;
import com.google.inject.Inject;
import java.math.BigDecimal;
import javax.persistence.PersistenceException;
public class AccountingReportManagementRepository extends AccountingReportRepository {
@Inject protected AccountingReportService accountingReportService;
@Override
public AccountingReport save(AccountingReport accountingReport) {
try {
if (accountingReport.getRef() == null) {
String seq = accountingReportService.getSequence(accountingReport);
accountingReportService.setSequence(accountingReport, seq);
}
return super.save(accountingReport);
} catch (Exception e) {
JPA.em().getTransaction().rollback();
JPA.runInTransaction(() -> TraceBackService.trace(e));
JPA.em().getTransaction().begin();
throw new PersistenceException(e.getLocalizedMessage());
}
}
@Override
public AccountingReport copy(AccountingReport entity, boolean deep) {
AccountingReport copy = super.copy(entity, deep);
copy.setRef(null);
copy.setStatusSelect(this.STATUS_DRAFT);
copy.setPublicationDateTime(null);
copy.setTotalDebit(BigDecimal.ZERO);
copy.setTotalCredit(BigDecimal.ZERO);
copy.setBalance(BigDecimal.ZERO);
return copy;
}
}

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.account.db.repo;
import com.axelor.apps.account.db.AnalyticMoveLine;
public class AnalyticMoveLineMngtRepository extends AnalyticMoveLineRepository {
@Override
public AnalyticMoveLine copy(AnalyticMoveLine entity, boolean deep) {
AnalyticMoveLine copy = super.copy(entity, deep);
copy.setMoveLine(null);
copy.setInvoiceLine(null);
return copy;
}
}

View File

@ -0,0 +1,75 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.db.repo;
import com.axelor.apps.account.db.DepositSlip;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.Sequence;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.exception.service.TraceBackService;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.common.base.Strings;
import javax.persistence.PersistenceException;
public class DepositSlipAccountRepository extends DepositSlipRepository {
@Override
public DepositSlip save(DepositSlip entity) {
try {
if (Strings.isNullOrEmpty(entity.getDepositNumber())) {
setDepositNumber(entity);
}
return super.save(entity);
} catch (Exception e) {
TraceBackService.trace(e);
throw new PersistenceException(e.getLocalizedMessage());
}
}
private void setDepositNumber(DepositSlip entity) throws AxelorException {
SequenceService sequenceService = Beans.get(SequenceService.class);
String depositNumber =
sequenceService.getSequenceNumber(SequenceRepository.DEPOSIT_SLIP, entity.getCompany());
if (Strings.isNullOrEmpty(depositNumber)) {
throw new AxelorException(
Sequence.class,
TraceBackRepository.CATEGORY_NO_VALUE,
I18n.get(IExceptionMessage.DEPOSIT_SLIP_MISSING_SEQUENCE),
entity.getCompany().getName());
}
entity.setDepositNumber(depositNumber);
}
@Override
public void remove(DepositSlip entity) {
if (entity.getPublicationDate() != null) {
throw new PersistenceException(I18n.get(IExceptionMessage.DEPOSIT_SLIP_CANNOT_DELETE));
}
entity.clearPaymentVoucherList();
super.remove(entity);
}
}

View File

@ -0,0 +1,72 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.db.repo;
import com.axelor.apps.account.db.FixedAsset;
import com.axelor.apps.account.service.FixedAssetService;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.inject.Beans;
import com.google.common.base.Strings;
import java.math.BigDecimal;
import javax.persistence.PersistenceException;
public class FixedAssetManagementRepository extends FixedAssetRepository {
@Override
public FixedAsset save(FixedAsset fixedAsset) {
try {
computeReference(fixedAsset);
computeDepreciation(fixedAsset);
return super.save(fixedAsset);
} catch (Exception e) {
e.printStackTrace();
throw new PersistenceException(e);
}
}
private void computeReference(FixedAsset fixedAsset) {
try {
if (fixedAsset.getId() != null && Strings.isNullOrEmpty(fixedAsset.getReference())) {
fixedAsset.setReference(
Beans.get(SequenceService.class).getDraftSequenceNumber(fixedAsset));
}
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
private void computeDepreciation(FixedAsset fixedAsset) {
if ((fixedAsset.getFixedAssetLineList() == null || fixedAsset.getFixedAssetLineList().isEmpty())
&& fixedAsset.getGrossValue().compareTo(BigDecimal.ZERO) > 0) {
Beans.get(FixedAssetService.class).generateAndcomputeLines(fixedAsset);
}
}
@Override
public FixedAsset copy(FixedAsset entity, boolean deep) {
FixedAsset copy = super.copy(entity, deep);
copy.setStatusSelect(STATUS_DRAFT);
copy.setReference(null);
copy.setResidualValue(entity.getGrossValue());
copy.setFixedAssetLineList(null);
return copy;
}
}

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.account.db.repo;
import com.axelor.apps.account.db.InvoiceBatch;
public class InvoiceBatchAccountRepository extends InvoiceBatchRepository {
@Override
public InvoiceBatch copy(InvoiceBatch entity, boolean deep) {
InvoiceBatch copy = super.copy(entity, deep);
copy.setBatchList(null);
return copy;
}
}

View File

@ -0,0 +1,102 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.db.repo;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.SubrogationRelease;
import com.axelor.apps.account.service.invoice.InvoiceService;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import java.math.BigDecimal;
import java.util.Map;
import javax.persistence.PersistenceException;
public class InvoiceManagementRepository extends InvoiceRepository {
@Override
public Invoice copy(Invoice entity, boolean deep) {
Invoice copy = super.copy(entity, deep);
copy.setStatusSelect(STATUS_DRAFT);
copy.setInvoiceId(null);
copy.setInvoiceDate(null);
copy.setDueDate(null);
copy.setValidatedByUser(null);
copy.setMove(null);
copy.setOriginalInvoice(null);
copy.setCompanyInTaxTotalRemaining(BigDecimal.ZERO);
copy.setAmountPaid(BigDecimal.ZERO);
copy.setIrrecoverableStatusSelect(IRRECOVERABLE_STATUS_NOT_IRRECOUVRABLE);
copy.setAmountRejected(BigDecimal.ZERO);
copy.clearBatchSet();
copy.setDebitNumber(null);
copy.setDirectDebitManagement(null);
copy.setDoubtfulCustomerOk(false);
copy.setMove(null);
copy.setInterbankCodeLine(null);
copy.setPaymentMove(null);
copy.clearRefundInvoiceList();
copy.setRejectDate(null);
copy.setOriginalInvoice(null);
copy.setUsherPassageOk(false);
copy.setAlreadyPrintedOk(false);
copy.setCanceledPaymentSchedule(null);
copy.setDirectDebitAmount(BigDecimal.ZERO);
copy.setImportId(null);
copy.setPartnerAccount(null);
copy.setJournal(null);
copy.clearInvoicePaymentList();
copy.setPrintedPDF(null);
copy.setValidatedDate(null);
copy.setVentilatedByUser(null);
copy.setVentilatedDate(null);
copy.setPfpValidateStatusSelect(PFP_STATUS_AWAITING);
copy.setDecisionPfpTakenDate(null);
return copy;
}
@Override
public Invoice save(Invoice invoice) {
try {
invoice = super.save(invoice);
Beans.get(InvoiceService.class).setSequence(invoice);
return invoice;
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public Map<String, Object> populate(Map<String, Object> json, Map<String, Object> context) {
try {
if (context.get("_model") != null
&& context.get("_model").toString().contains("SubrogationRelease")) {
long id = (long) context.get("id");
SubrogationRelease subrogationRelease =
Beans.get(SubrogationReleaseRepository.class).find(id);
json.put("$subrogationStatusSelect", subrogationRelease.getStatusSelect());
}
} catch (Exception e) {
TraceBackService.trace(e);
}
return super.populate(json, context);
}
}

View File

@ -0,0 +1,38 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.db.repo;
import com.axelor.apps.account.db.InvoicePayment;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentValidateService;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import javax.persistence.PersistenceException;
public class InvoicePaymentManagementRepository extends InvoicePaymentRepository {
@Override
public InvoicePayment save(InvoicePayment invoicePayment) {
try {
Beans.get(InvoicePaymentValidateService.class).validate(invoicePayment);
return super.save(invoicePayment);
} catch (Exception e) {
TraceBackService.trace(e);
throw new PersistenceException(e);
}
}
}

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.account.db.repo;
import com.axelor.apps.account.db.Journal;
public class JournalManagementRepository extends JournalRepository {
@Override
public Journal copy(Journal entity, boolean deep) {
Journal copy = super.copy(entity, deep);
copy.setStatusSelect(JournalRepository.STATUS_INACTIVE);
copy.setSequence(null);
return copy;
}
}

View File

@ -0,0 +1,65 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.db.repo;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import java.util.List;
import javax.persistence.PersistenceException;
public class MoveLineManagementRepository extends MoveLineRepository {
@Override
public void remove(MoveLine entity) {
if (!entity.getMove().getStatusSelect().equals(MoveRepository.STATUS_NEW)) {
try {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.MOVE_REMOVE_NOT_OK),
entity.getMove().getReference());
} catch (AxelorException e) {
throw new PersistenceException(e);
}
} else {
super.remove(entity);
}
}
@Override
public MoveLine save(MoveLine entity) {
List<AnalyticMoveLine> analyticMoveLineList = entity.getAnalyticMoveLineList();
if (analyticMoveLineList != null) {
for (AnalyticMoveLine analyticMoveLine : analyticMoveLineList) {
analyticMoveLine.setAccount(entity.getAccount());
analyticMoveLine.setAccountType(entity.getAccount().getAccountType());
}
}
try {
Beans.get(MoveLineService.class).validateMoveLine(entity);
} catch (Exception e) {
throw new PersistenceException(e);
}
return super.save(entity);
}
}

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.account.db.repo;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.move.MoveSequenceService;
import com.axelor.apps.account.service.move.MoveValidateService;
import com.axelor.apps.base.db.Period;
import com.axelor.apps.base.db.repo.YearRepository;
import com.axelor.apps.base.service.PeriodService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import java.time.LocalDate;
import java.util.List;
import javax.persistence.PersistenceException;
public class MoveManagementRepository extends MoveRepository {
@Override
public Move copy(Move entity, boolean deep) {
Move copy = super.copy(entity, deep);
copy.setDate(Beans.get(AppBaseService.class).getTodayDate());
Period period = null;
try {
period =
Beans.get(PeriodService.class)
.getActivePeriod(copy.getDate(), entity.getCompany(), YearRepository.TYPE_FISCAL);
} catch (AxelorException e) {
throw new PersistenceException(e.getLocalizedMessage());
}
copy.setStatusSelect(STATUS_NEW);
copy.setReference(null);
copy.setExportNumber(null);
copy.setExportDate(null);
copy.setAccountingReport(null);
copy.setValidationDate(null);
copy.setPeriod(period);
copy.setAccountingOk(false);
copy.setIgnoreInDebtRecoveryOk(false);
copy.setPaymentVoucher(null);
copy.setRejectOk(false);
copy.setInvoice(null);
List<MoveLine> moveLineList = copy.getMoveLineList();
if (moveLineList != null) {
moveLineList.forEach(moveLine -> resetMoveLine(moveLine, copy.getDate()));
}
return copy;
}
public void resetMoveLine(MoveLine moveLine, LocalDate date) {
moveLine.setInvoiceReject(null);
moveLine.setDate(date);
moveLine.setExportedDirectDebitOk(false);
moveLine.setReimbursementStatusSelect(MoveLineRepository.REIMBURSEMENT_STATUS_NULL);
List<AnalyticMoveLine> analyticMoveLineList = moveLine.getAnalyticMoveLineList();
if (analyticMoveLineList != null) {
moveLine.getAnalyticMoveLineList().forEach(line -> line.setDate(moveLine.getDate()));
}
}
@Override
public Move save(Move move) {
try {
if (move.getStatusSelect() == MoveRepository.STATUS_DAYBOOK) {
Beans.get(MoveValidateService.class).checkPreconditions(move);
}
Beans.get(MoveSequenceService.class).setDraftSequence(move);
List<MoveLine> moveLineList = move.getMoveLineList();
if (moveLineList != null) {
for (MoveLine moveLine : moveLineList) {
List<AnalyticMoveLine> analyticMoveLineList = moveLine.getAnalyticMoveLineList();
if (analyticMoveLineList != null) {
for (AnalyticMoveLine analyticMoveLine : analyticMoveLineList) {
analyticMoveLine.setAccount(moveLine.getAccount());
analyticMoveLine.setAccountType(moveLine.getAccount().getAccountType());
}
}
}
}
return super.save(move);
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
@Override
public void remove(Move entity) {
if (!entity.getStatusSelect().equals(MoveRepository.STATUS_NEW)) {
try {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.MOVE_REMOVE_NOT_OK),
entity.getReference());
} catch (AxelorException e) {
throw new PersistenceException(e);
}
} else {
super.remove(entity);
}
}
}

View File

@ -0,0 +1,86 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.db.repo;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.account.service.AccountingSituationService;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.PartnerBaseRepository;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.service.app.AppService;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import javax.persistence.PersistenceException;
import org.apache.commons.collections.CollectionUtils;
@Singleton
public class PartnerAccountRepository extends PartnerBaseRepository {
private AppService appService;
private AccountingSituationService accountingSituationService;
@Inject
public PartnerAccountRepository(
AppService appService, AccountingSituationService accountingSituationService) {
this.appService = appService;
this.accountingSituationService = accountingSituationService;
}
@Override
public Partner save(Partner partner) {
try {
if (partner.getId() == null) {
partner = super.save(partner);
}
if (appService.isApp("account")) {
if (partner.getIsContact() == false || partner.getIsEmployee()) {
// Create & fill
Beans.get(AccountingSituationService.class)
.createAccountingSituation(Beans.get(PartnerRepository.class).find(partner.getId()));
}
// We do this for contacts too as it seems this is the way employees are handled
if (CollectionUtils.isNotEmpty(partner.getAccountingSituationList())) {
for (AccountingSituation situation : partner.getAccountingSituationList()) {
accountingSituationService.createPartnerAccounts(situation);
}
}
}
return super.save(partner);
} catch (Exception e) {
throw new PersistenceException(e);
}
}
@Override
public Partner copy(Partner partner, boolean deep) {
Partner copy = super.copy(partner, deep);
if (appService.isApp("account")) {
copy.setAccountingSituationList(null);
}
return copy;
}
}

View File

@ -0,0 +1,69 @@
/*
* 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.account.db.repo;
import com.axelor.apps.account.db.PaymentVoucher;
import com.axelor.apps.account.service.payment.paymentvoucher.PaymentVoucherSequenceService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.service.TraceBackService;
import com.axelor.inject.Beans;
import javax.persistence.PersistenceException;
public class PaymentVoucherManagementRepository extends PaymentVoucherRepository {
@Override
public PaymentVoucher copy(PaymentVoucher entity, boolean deep) {
/**
* copy set are commented because there is a lot of vouchers that contains the same element to pay but partially
*/
PaymentVoucher copy = super.copy(entity, deep);
copy.setStatusSelect(STATUS_DRAFT);
copy.setRef(null);
copy.setPaymentDate(Beans.get(AppBaseService.class).getTodayDate());
// copy.clearPayVoucherDueElementList();
// copy.clearPayVoucherElementToPayList();
copy.setGeneratedMove(null);
copy.setBankCardTransactionNumber(null);
copy.clearBatchSet();
copy.setImportId(null);
copy.setReceiptNo(null);
// copy.setRemainingAmount(null);
// copy.setRemainingAllocatedAmount(null);
copy.setToSaveEmailOk(false);
copy.setDefaultEmailOk(false);
copy.setEmail(null);
return copy;
}
@Override
public PaymentVoucher save(PaymentVoucher paymentVoucher) {
try {
Beans.get(PaymentVoucherSequenceService.class).setReference(paymentVoucher);
return super.save(paymentVoucher);
} catch (Exception e) {
TraceBackService.trace(e);
throw new PersistenceException(e.getLocalizedMessage());
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.db.repo;
import com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.apps.account.service.ReconcileGroupSequenceService;
import com.axelor.inject.Beans;
import com.google.common.base.Strings;
import javax.persistence.PersistenceException;
public class ReconcileGroupAccountRepository extends ReconcileGroupRepository {
/** On first reconcile group save (e.g. when the code is not filled), we fill the sequence. */
@Override
public ReconcileGroup save(ReconcileGroup reconcileGroup) {
try {
if (Strings.isNullOrEmpty(reconcileGroup.getCode())) {
Beans.get(ReconcileGroupSequenceService.class).fillCodeFromSequence(reconcileGroup);
}
return super.save(reconcileGroup);
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
}

View File

@ -0,0 +1,72 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.db.repo;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.ReconcileSequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import javax.persistence.PersistenceException;
public class ReconcileManagementRepository extends ReconcileRepository {
@Override
public Reconcile save(Reconcile reconcile) {
try {
Beans.get(ReconcileSequenceService.class).setDraftSequence(reconcile);
return super.save(reconcile);
} catch (Exception e) {
throw new PersistenceException(e.getLocalizedMessage());
}
}
@Override
public Reconcile copy(Reconcile reconcile, boolean deep) {
Reconcile copy = super.copy(reconcile, deep);
copy.setCanBeZeroBalanceOk(false);
copy.setMustBeZeroBalanceOk(false);
copy.setReconcileSeq(null);
copy.setStatusSelect(ReconcileRepository.STATUS_DRAFT);
return copy;
}
@Override
public void remove(Reconcile entity) {
if (!entity.getStatusSelect().equals(ReconcileRepository.STATUS_DRAFT)) {
try {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.RECONCILE_CAN_NOT_BE_REMOVE),
entity.getReconcileSeq());
} catch (AxelorException e) {
throw new PersistenceException(e);
}
} else {
super.remove(entity);
}
}
}

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.account.db.repo;
import com.axelor.apps.account.db.SubrogationRelease;
public class SubrogationReleaseManagementRepository extends SubrogationReleaseRepository {
@Override
public SubrogationRelease copy(SubrogationRelease entity, boolean deep) {
SubrogationRelease srCopy = super.copy(entity, deep);
srCopy.setStatusSelect(STATUS_NEW);
srCopy.clearInvoiceSet();
return srCopy;
}
}

View File

@ -0,0 +1,804 @@
/*
* 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.account.exception;
/**
* Interface of Exceptions. Enum all exception of axelor-account.
*
* @author dubaux
*/
public interface IExceptionMessage {
static final String INVOICE_LINE_TAX_LINE = /*$$(*/ "A tax line is missing" /*)*/;
/** Bank statement service */
static final String BANK_STATEMENT_1 = /*$$(*/
"%s : Computed balance and Ending Balance must be equal" /*)*/;
static final String BANK_STATEMENT_2 = /*$$(*/
"%s : MoveLine amount is not equals with bank statement line %s" /*)*/;
static final String BANK_STATEMENT_3 = /*$$(*/
"%s : Bank statement line %s amount can't be null" /*)*/;
/** Move service */
static final String NO_MOVES_SELECTED = /*$$(*/
"Please select 'Draft' or 'Simulated' moves" /*)*/;
static final String MOVE_VALIDATION_NOT_OK = /*$$(*/
"Error in move validation, please check the log" /*)*/;
static final String MOVE_VALIDATION_OK = /*$$(*/ "Moves validated successfully" /*)*/;
static final String MOVE_ARCHIVE_NOT_OK = /*$$(*/ "You can't archive this move %s" /*)*/;
static final String MOVE_REMOVE_NOT_OK = /*$$(*/ "You can't remove this move %s" /*)*/;
static final String MOVE_REMOVED_OK = /*$$(*/ "Move(s) has been removed successfully" /*)*/;
static final String MOVE_ARCHIVE_OK = /*$$(*/ "Move(s) has been archived successfully" /*)*/;
static final String NO_MOVE_TO_REMOVE_OR_ARCHIVE = /*$$(*/
"Please select 'Draft' or 'Daybook' or 'Canceled' moves" /*)*/;
static final String MOVE_ARCHIVE_OR_REMOVE_OK = /*$$(*/
"Move(s) has been removed or archived successfully" /*)*/;
static final String MOVE_ARCHIVE_OR_REMOVE_NOT_OK = /*$$(*/
"Error in move deleting or archiving, please check the log" /*)*/;
static final String MOVE_ARCHIVE_NOT_OK_BECAUSE_OF_LINK_WITH = /*$$(*/
"This move %s can not be archived because it is linked to another piece named %s." /*)*/;
static final String MOVE_LINE_ARCHIVE_NOT_OK_BECAUSE_OF_LINK_WITH = /*$$(*/
"This move line %s can not be archived because it is linked to another piece named %s." /*)*/;
static final String MOVE_ARCHIVE_OR_REMOVE_NOT_OK_NB = /*$$(*/
"%d moves couldn't be deleted or archived, please check the logs." /*)*/;
/** Account management service */
static final String ACCOUNT_MANAGEMENT_1_ACCOUNT = /*$$(*/
"Accounting configuration is missing for Product: %s (company: %s)" /*)*/;
/** AccountingSituationService * */
static final String ACCOUNTING_SITUATION_1 = /*$$(*/
"You have to enter a prefix for automatic customer account creation in accounting application parameters of company %s" /*)*/;
static final String ACCOUNTING_SITUATION_2 = /*$$(*/
"You have to select a sequence for automatic customer account creation in accounting application parameters of company %s" /*)*/;
static final String ACCOUNTING_SITUATION_3 = /*$$(*/
"Invalid automatic partner account creation mode, this is a bug that should be reported." /*)*/;
static final String ACCOUNTING_SITUATION_4 = /*$$(*/
"You have to enter a prefix for automatic supplier account creation in accounting application parameters of company %s" /*)*/;
static final String ACCOUNTING_SITUATION_5 = /*$$(*/
"You have to select a sequence for automatic supplier account creation in accounting application parameters of company %s" /*)*/;
static final String ACCOUNTING_SITUATION_6 = /*$$(*/
"You have to enter a prefix for automatic employee account creation in accounting application parameters of company %s" /*)*/;
static final String ACCOUNTING_SITUATION_7 = /*$$(*/
"You have to select a sequence for automatic employee account creation in accounting application parameters of company %s" /*)*/;
/** Mail service */
static final String MAIL_1 = /*$$(*/
"%s : Please define an email template for cash register (company: %s)" /*)*/;
/** Account clearance service and controller */
static final String ACCOUNT_CLEARANCE_1 = /*$$(*/
"%s : You must configure account informations for the company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_2 = /*$$(*/
"%s : You must configure a financial account for then company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_3 = /*$$(*/
"%s : You must configure a tax standard rate for the company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_4 = /*$$(*/
"%s : You must configure account clearance for the company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_5 = /*$$(*/
"%s : You must configure a clearance sequence of the overpayments for the company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_6 = /*$$(*/
"%s : You must configure an overpayment account clearance journal for the company %s" /*)*/;
static final String ACCOUNT_CLEARANCE_7 = /*$$(*/ "Move lines generated" /*)*/;
/** Account customer service */
static final String ACCOUNT_CUSTOMER_1 = /*$$(*/
"%s : A customer account is missing for the company %s" /*)*/;
static final String ACCOUNT_CUSTOMER_2 = /*$$(*/
"%s : A supplier account is missing for the company %s" /*)*/;
/** Check rejection service */
static final String CHECK_REJECTION_1 = /*$$(*/
"%s : You must configure a cheque rejection sequence for the company %s" /*)*/;
/** Irrecoverable service and controller */
static final String IRRECOVERABLE_1 = /*$$(*/ "Timetable line %s" /*)*/;
static final String IRRECOVERABLE_2 = /*$$(*/
"%s : Error generated on invoice creation shift to irrecoverable %s" /*)*/;
static final String IRRECOVERABLE_3 = /*$$(*/
"%s : The invoice %s has no accounting document whose the remainder to be paid is positive" /*)*/;
static final String IRRECOVERABLE_4 = /*$$(*/
"%s : You must configure shit to irrecoverable sequence for the company %s" /*)*/;
static final String IRRECOVERABLE_5 = /*$$(*/ "Treatment finished" /*)*/;
static final String IRRECOVERABLE_6 = /*$$(*/ "Anomalies generated" /*)*/;
static final String IRRECOVERABLE_7 = /*$$(*/ "You must select a printing type" /*)*/;
/** Journal service */
static final String JOURNAL_1 = /*$$(*/ "Invoice type missing on invoice %s" /*)*/;
/** Move line export service */
static final String MOVE_LINE_EXPORT_1 = /*$$(*/
"%s : Error : You must configure a sale interface sequence for the company %s" /*)*/;
static final String MOVE_LINE_EXPORT_2 = /*$$(*/
"%s : Error : You must configure a credit note interface sequence for the company %s" /*)*/;
static final String MOVE_LINE_EXPORT_3 = /*$$(*/
"%s : Error : You must configure a treasury interface sequence for the company %s" /*)*/;
static final String MOVE_LINE_EXPORT_4 = /*$$(*/
"%s : Error : You must configure a purchase interface sequence for the company %s" /*)*/;
static final String MOVE_LINE_EXPORT_YEAR_OR_PERIOD_OR_DATE_IS_NULL = /*$$(*/
"Year or period or date is null, you must set a period." /*)*/;
/** Accounting report service and controller */
static final String ACCOUNTING_REPORT_1 = /*$$(*/
"%s : Error : You must configure an account reporting sequence for the company %s" /*)*/;
static final String ACCOUNTING_REPORT_2 = /*$$(*/
"%s : Error : You must configure an account export sequence for the company %s" /*)*/;
static final String ACCOUNTING_REPORT_3 = /*$$(*/ "Move lines recovered" /*)*/;
static final String ACCOUNTING_REPORT_4 = /*$$(*/ "You must select an export type" /*)*/;
static final String ACCOUNTING_REPORT_6 = /*$$(*/ "Moves exported" /*)*/;
static final String ACCOUNTING_REPORT_UNKNOWN_ACCOUNTING_REPORT_TYPE = /*$$(*/
"Unknown accounting report type: %d" /*)*/;
static final String ACCOUNTING_REPORT_ANALYTIC_REPORT = /*$$(*/
"%s : Error : You must configure an analytic report sequence for the company %s" /*)*/;
/** Move line service */
static final String MOVE_LINE_1 = /*$$(*/ "Partner is missing on the invoice %s" /*)*/;
static final String MOVE_LINE_2 = /*$$(*/ "Partner account missing on the invoice %s" /*)*/;
static final String MOVE_LINE_4 = /*$$(*/
"Account missing on configuration for line : %s (company : %s)" /*)*/;
static final String MOVE_LINE_5 = /*$$(*/
"Analytic account %s associated to sales account for the product %s is not configured : (company : %s)" /*)*/;
static final String MOVE_LINE_6 = /*$$(*/
"Account missing on the tax line : %s (company : %s)" /*)*/;
static final String ANALYTIC_DISTRIBUTION_MISSING = /*$$(*/
"Analytic distribution is missing on configuration for line : %s (company : %s)" /*)*/;
static final String MOVE_LINE_7 = /*$$(*/
"The accounting move line on the account %s can't have an amount equals to zero" /*)*/;
/** Move service */
static final String MOVE_1 = /*$$(*/ "Invoice type missing on invoice %s" /*)*/;
static final String MOVE_2 = /*$$(*/ "You must select a journal for the move %s" /*)*/;
static final String MOVE_3 = /*$$(*/ "You must select a company for the move %s" /*)*/;
static final String MOVE_4 = /*$$(*/ "You must select a period for the move %s" /*)*/;
static final String MOVE_5 = /*$$(*/
"Journal %s does not have any account move sequence configured" /*)*/;
static final String MOVE_6 = /*$$(*/ "Move account sens %s can't be determined" /*)*/;
static final String MOVE_7 = /*$$(*/
"Account move %s has a total debit different than total credit : %s <> %s" /*)*/;
static final String MOVE_8 = /*$$(*/ "The move %s cannot be empty" /*)*/;
static final String MOVE_9 = /*$$(*/
"Tax is mandatory for the account %s on the move line %s" /*)*/;
static final String MOVE_10 = /*$$(*/
"Analytic distribution template is mandatory for the account %s on the move line %s." /*)*/;
static final String MOVE_11 = /*$$(*/
"An analytic distribution is set in move line %s but the account used do not allow analytic distribution" /*)*/;
static final String MOVE_VALIDATION_FISCAL_PERIOD_CLOSED = /*$$(*/
"Accounting move can not be validated because its fiscal period is closed." /*)*/;
/** Payment schedule export service */
static final String PAYMENT_SCHEDULE_1 = /*$$(*/
"%s : You must configure a RIB for payment timetable %s" /*)*/;
static final String PAYMENT_SCHEDULE_2 = /*$$(*/
"%s : You must configure a RIB for the partner %s" /*)*/;
static final String PAYMENT_SCHEDULE_3 = /*$$(*/
"%s : Error : You must configure a direct debit date for the %s batch configuration" /*)*/;
static final String PAYMENT_SCHEDULE_4 = /*$$(*/
"%s : You must configure a direct debit reject sequence\n for the company %s for the journal %s" /*)*/;
static final String PAYMENT_SCHEDULE_5 = /*$$(*/
"You must configure a timetable sequence for the company %s" /*)*/;
static final String PAYMENT_SCHEDULE_6 = /*$$(*/
"%s : Error : You must, at first, create timetable lines for the timetable %s" /*)*/;
static final String PAYMENT_SCHEDULE_LINE_AMOUNT_MISMATCH = /*$$(*/
"The sum of line amounts (%s) must match the amount of the payment schedule (%s)." /*)*/;
/** Reconcile service */
static final String RECONCILE_1 = /*$$(*/
"%s : Reconciliation : You must fill concerned moves lines." /*)*/;
static final String RECONCILE_2 = /*$$(*/
"%s : Reconciliation : Move line accounts are not compatible." /*)*/;
static final String RECONCILE_3 = /*$$(*/
"(Debit %s account %s amount %s - Credit %s account %s amount %s)" /*)*/;
static final String RECONCILE_4 = /*$$(*/
"%s : Reconciliation %s: Reconciliated amount must be different than zero. (Debit %s account %s - Credit %s account %s)" /*)*/;
static final String RECONCILE_5 = /*$$(*/
"%s : Reconciliation %s: Reconciliated amount (%s) must be lower or equal to remaining amount to reconciliate from moves lines." /*)*/;
static final String RECONCILE_6 = /*$$(*/
"%s : Error : You must configure a reconciliation sequence for the company %s" /*)*/;
static final String RECONCILE_7 = /*$$(*/
"Reconciliation : Selected moves lines must concern the same company. Reconcile : %s company \n Debit move line : %s company \n Credit move line : %s company" /*)*/;
static final String RECONCILE_CAN_NOT_BE_REMOVE = /*$$(*/
"The reconcile %s cannot be removed, please select draft reconcile(s)" /*)*/;
/** Reimbursement service and controller */
static final String REIMBURSEMENT_1 = /*$$(*/
"%s : You must configure a reimbursement sequence for the company %s" /*)*/;
static final String REIMBURSEMENT_2 = /*$$(*/
"Export reimbursement folder (SEPA format) has not been configured for the company %s." /*)*/;
static final String REIMBURSEMENT_3 = /*$$(*/
"No reimbursement found for the ref %s and the company %s." /*)*/;
static final String REIMBURSEMENT_4 = /*$$(*/ "You must configure a RIB." /*)*/;
/** Year service */
static final String YEAR_1 = /*$$(*/
"%s : You must configure a company for the fiscal year %s" /*)*/;
/** Batch Account customer */
static final String BATCH_ACCOUNT_1 = /*$$(*/ "Accounting situation %s" /*)*/;
static final String BATCH_ACCOUNT_2 = /*$$(*/
"Contact's account balances determination's reporting :" /*)*/;
static final String BATCH_ACCOUNT_3 = /*$$(*/ "* %s Account(s) situation(s) treated" /*)*/;
static final String BATCH_ACCOUNT_4 = /*$$(*/
"Account balances of %s accounting situation has not been updated, you must run the contact account batch update." /*)*/;
static final String BATCH_ACCOUNT_5 = /*$$(*/
"Account balances from all accounts situations (%s) has been updated." /*)*/;
/** Batch doubtful customer */
static final String BATCH_DOUBTFUL_1 = /*$$(*/
"Doubtful account's determination's reporting" /*)*/;
static final String BATCH_DOUBTFUL_2 = /*$$(*/ "* %s Invoice(s) treated" /*)*/;
/** Batch move line export */
static final String BATCH_MOVELINE_EXPORT_1 = /*$$(*/
"%s : Error : You must configure a company for the batch configurator %s" /*)*/;
static final String BATCH_MOVELINE_EXPORT_2 = /*$$(*/
"%s : Error : You must configure a due date for the batch configurator %s" /*)*/;
static final String BATCH_MOVELINE_EXPORT_3 = /*$$(*/
"%s : Error : You must configure an export type for the batch configurator %s" /*)*/;
static final String BATCH_MOVELINE_EXPORT_4 = /*$$(*/ "Moves export batch's reporting :" /*)*/;
static final String BATCH_MOVELINE_EXPORT_5 = /*$$(*/ "Moves Lines (Moves) exported" /*)*/;
/** Batch payment schedule import/export */
static final String BATCH_PAYMENT_SCHEDULE_1 = /*$$(*/
"Unknowned data type for the treatment %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_2 = /*$$(*/ "Direct debit's export batch %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_3 = /*$$(*/ "Due date's direct debit %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_4 = /*$$(*/
"Export reporting to invoices direct debits :" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_5 = /*$$(*/ "Invoice(s) direct debit(s) treated" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_6 = /*$$(*/
"Export reporting to monthly direct debits :" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_7 = /*$$(*/ "Monthly direct debit(s) treated" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_8 = /*$$(*/
"%s : No timetable nor invoice found for the direct debit number : %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_9 = /*$$(*/ "Reject %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_10 = /*$$(*/
"Timetable's reject move's creation %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_11 = /*$$(*/
"Invoice's reject move's creation %s" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_12 = /*$$(*/
"Reporting to direct debit reject's import :" /*)*/;
static final String BATCH_PAYMENT_SCHEDULE_13 = /*$$(*/ "Direct debit(s) rejected" /*)*/;
/** Batch reimbursement export/import */
static final String BATCH_REIMBURSEMENT_1 = /*$$(*/
"Bug(Anomaly) generated during SEPA export - Batch %s" /*)*/;
static final String BATCH_REIMBURSEMENT_2 = /*$$(*/ "Reporting to reimbursement creation :" /*)*/;
static final String BATCH_REIMBURSEMENT_3 = /*$$(*/ "Reimbursement(s) created" /*)*/;
static final String BATCH_REIMBURSEMENT_4 = /*$$(*/ "Reporting to reimbursement's export :" /*)*/;
static final String BATCH_REIMBURSEMENT_5 = /*$$(*/ "Reimbursement(s) treated" /*)*/;
static final String BATCH_REIMBURSEMENT_6 = /*$$(*/ "Reimbursement's import's batch %s" /*)*/;
static final String BATCH_REIMBURSEMENT_7 = /*$$(*/ "Reimbursement reject %s" /*)*/;
static final String BATCH_REIMBURSEMENT_8 = /*$$(*/
"Reporting to reimbursement reject's import :" /*)*/;
static final String BATCH_REIMBURSEMENT_9 = /*$$(*/ "Reimbursement(s) rejected" /*)*/;
static final String BATCH_REIMBURSEMENT_10 = /*$$(*/ "Total Amount" /*)*/;
/** Batch debt recovery */
static final String BATCH_DEBT_RECOVERY_1 = /*$$(*/ "Debt recovery's reporting :" /*)*/;
static final String BATCH_DEBT_RECOVERY_2 = /*$$(*/ "Partner(s) treated" /*)*/;
/** Batch credit transfer */
static final String BATCH_CREDIT_TRANSFER_REPORT_TITLE = /*$$(*/
"Report for credit transfer batch:" /*)*/;
static final String BATCH_CREDIT_TRANSFER_INVOICE_DONE_SINGULAR = /*$$(*/
"%d invoice treated successfully," /*)*/;
static final String BATCH_CREDIT_TRANSFER_INVOICE_DONE_PLURAL = /*$$(*/
"%d invoices treated successfully," /*)*/;
static final String BATCH_CREDIT_TRANSFER_REIMBURSEMENT_DONE_SINGULAR = /*$$(*/
"%d reimbursement created successfully," /*)*/;
static final String BATCH_CREDIT_TRANSFER_REIMBURSEMENT_DONE_PLURAL = /*$$(*/
"%d reimbursements created successfully," /*)*/;
static final String BATCH_CREDIT_TRANSFER_ANOMALY_SINGULAR = /*$$(*/ "%d anomaly." /*)*/;
static final String BATCH_CREDIT_TRANSFER_ANOMALY_PLURAL = /*$$(*/ "%d anomalies." /*)*/;
/** Batch strategy */
static final String BATCH_STRATEGY_1 = /*$$(*/
"%s : You must configure a RIB for batch's configurator %s" /*)*/;
/** Batch realize fixed asset lines */
static final String BATCH_REALIZED_FIXED_ASSET_LINE = /*$$(*/ "Realized fixed asset lines" /*)*/;
/** Batch close / open the year account */
static final String BATCH_CLOSE_OPEN_ANNUAL_ACCOUNT_REPORT_TITLE = /*$$(*/
"Report for close/open annual accounts batch:" /*)*/;
static final String BATCH_CLOSE_OPEN_ANNUAL_ACCOUNT_DONE_SINGULAR = /*$$(*/
"%d account treated successfully," /*)*/;
static final String BATCH_CLOSE_OPEN_ANNUAL_ACCOUNT_DONE_PLURAL = /*$$(*/
"%d accounts treated successfully," /*)*/;
/** Cfonb export service */
static final String CFONB_EXPORT_1 = /*$$(*/
"You must configure a RIB for the reimbursement" /*)*/;
static final String CFONB_EXPORT_2 = /*$$(*/
"%s : Error detected during CFONB file's writing : %s" /*)*/;
static final String CFONB_EXPORT_3 = /*$$(*/
"%s : You must configure a Sort Code for the RIB %s of third-payer %s" /*)*/;
static final String CFONB_EXPORT_4 = /*$$(*/
"%s : You must configure a number's account for the RIB %s of third-payer %s" /*)*/;
static final String CFONB_EXPORT_5 = /*$$(*/
"%s : You must configure a Bank Code for the RIB %s of third-payer %s" /*)*/;
static final String CFONB_EXPORT_6 = /*$$(*/
"%s : You must configure a Bank Address for the RIB %s of third-payer %s" /*)*/;
/** Cfonb import service */
static final String CFONB_IMPORT_1 = /*$$(*/
"%s : You must configure a reject/return reason's code's list relating to Card cashing, Direct debit and TIP in general configuration" /*)*/;
static final String CFONB_IMPORT_2 = /*$$(*/
"%s : A header record is missing in the file %s" /*)*/;
static final String CFONB_IMPORT_3 = /*$$(*/
"%s : One or several detail records are missing in the file %s" /*)*/;
static final String CFONB_IMPORT_4 = /*$$(*/ "%s : A record is missing in the file %s" /*)*/;
static final String CFONB_IMPORT_5 = /*$$(*/
"%s : The total amount for the following record isn't correct (file %s) :\n %s" /*)*/;
static final String CFONB_IMPORT_6 = /*$$(*/
"%s : No payment mode found for the code %s and the company %s" /*)*/;
/** Cfonb tool service */
static final String CFONB_TOOL_NB_OF_CHAR_PER_LINE = /*$$(*/
"The record is not %s characters" /*)*/;
static final String CFONB_TOOL_EMPTY_ZONE = /*$$(*/ "Zone %s is empty" /*)*/;
static final String CFONB_TOOL_DIGITAL_ZONE_NOT_CORRECT = /*$$(*/
"Zone %s (%s) must be of the numeric type" /*)*/;
static final String CFONB_TOOL_1 = /*$$(*/
"%s : Anomaly detected (value isn't numeric : %s) for sender" /*)*/;
static final String CFONB_TOOL_2 = /*$$(*/
"%s : Anomaly detected (value isn't numeric : %s) for the receiver" /*)*/;
static final String CFONB_TOOL_3 = /*$$(*/
"%s : Anomaly detected (value isn't numeric : %s) for the total" /*)*/;
static final String CFONB_TOOL_4 = /*$$(*/
"%s : Anomaly detected (the record doesn't have %s characters : %s) for the record %s, company %s" /*)*/;
static final String COMPANY_CURRENCY = /*$$(*/
"%s : Please, configure a currency for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_1 = /*$$(*/
"%s : You must configure account's informations for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_2 = /*$$(*/
"%s : You must configure a CFONB format reimbursement's export's folder for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_3 = /*$$(*/
"%s : You must configure a CFONB format direct debit's export's folder for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_4 = /*$$(*/
"%s : You must configure a TIP and cheque TIP payment's import path for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_5 = /*$$(*/
"%s : You must configure a TIP and cheque TIP temporary import path for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_6 = /*$$(*/
"%s : You must configure a TIP and cheque TIP payment rejects path for the import file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_7 = /*$$(*/
"%s : You must configure a TIP and cheque TIP temporary path for the payment reject's file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_8 = /*$$(*/
"%s : You must configure a path for the reject's file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_9 = /*$$(*/
"%s : You must configure a path for the temporary reject's file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_10 = /*$$(*/
"%s : You must configure a path for the reimbursements rejects import's file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_11 = /*$$(*/
"%s : You must configure a path for the reimbursement rejects import's temporary file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_12 = /*$$(*/
"%s : You must configure a rejects journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_13 = /*$$(*/
"%s : You must configure an irrevocable journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_14 = /*$$(*/
"%s : You must configure a Supplier purchase journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_15 = /*$$(*/
"%s : You must configure a Supplier credit note journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_16 = /*$$(*/
"%s : You must configure a Sales journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_17 = /*$$(*/
"%s : You must configure a Customer credit note journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_18 = /*$$(*/
"%s : You must configure a Misc. Operation journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_19 = /*$$(*/
"%s : You must configure a Reimbursement journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_20 = /*$$(*/
"%s : You must configure a Sales journal type for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_21 = /*$$(*/
"%s : You must configure a Credit note journal type for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_22 = /*$$(*/
"%s : You must configure a Cash journal type for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_23 = /*$$(*/
"%s : You must configure a Purchase journal type for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_24 = /*$$(*/
"%s : You must configure an irrevocable doubtful account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_25 = /*$$(*/
"%s : You must configure a customer account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_26 = /*$$(*/
"%s : You must configure a supplier account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_27 = /*$$(*/
"%s : You must configure a cash difference account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_28 = /*$$(*/
"%s : You must configure a reimbursement account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_29 = /*$$(*/
"%s : You must configure a doubtful customer account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_30 = /*$$(*/
"%s : You must configure a direct debit payment mode for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_31 = /*$$(*/
"%s : You must configure a payment mode after reject for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_32 = /*$$(*/
"%s : You must configure a shift to irrecoverable's reason for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_34 = /*$$(*/
"%s : You must configure a reject import letter template for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_35 = /*$$(*/
"%s : You must configure a shifting reason (debt more than six months) for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_36 = /*$$(*/
"%s : You must configure a shifting reason (debt more than three months) for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_37 = /*$$(*/
"%s : You must configure a debt recovery tab for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_38 = /*$$(*/
"%s : You must configure an advance payment account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_39 = /*$$(*/
"%s : You must configure a file name for the export of move file for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_40 = /*$$(*/
"%s : You must configure an employee account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_41 = /*$$(*/
"%s : You must configure a factor credit account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_42 = /*$$(*/
"%s : You must configure a factor debit account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_43 = /*$$(*/
"%s : You must configure a year opening account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_44 = /*$$(*/
"%s : You must configure a year closure account for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_45 = /*$$(*/
"%s : You must configure a reported balance journal for the company %s" /*)*/;
static final String ACCOUNT_CONFIG_SEQUENCE_1 = /*$$(*/
"%s : Please, configure a sequence for the customer invoices and the company %s" /*)*/;
static final String ACCOUNT_CONFIG_SEQUENCE_2 = /*$$(*/
"%s : Please, configure a sequence for the customer refunds and the company %s" /*)*/;
static final String ACCOUNT_CONFIG_SEQUENCE_3 = /*$$(*/
"%s : Please, configure a sequence for the supplier invoices and the company %s" /*)*/;
static final String ACCOUNT_CONFIG_SEQUENCE_4 = /*$$(*/
"%s : Please, configure a sequence for the supplier refunds and the company %s" /*)*/;
/** Cfonb config service */
static final String CFONB_CONFIG_1 = /*$$(*/
"%s : You must configure CFONB for the company %s" /*)*/;
static final String CFONB_CONFIG_2 = /*$$(*/
"%s : You must configure a CFONB sender code register for the company %s" /*)*/;
static final String CFONB_CONFIG_3 = /*$$(*/
"%s : You must configure a CFONB sender's number for the company %s" /*)*/;
static final String CFONB_CONFIG_4 = /*$$(*/
"%s : You must configure a CFONB sender's name/corporate name for the company %s" /*)*/;
static final String CFONB_CONFIG_5 = /*$$(*/
"%s : You must configure a CFONB receiver code register for the company %s" /*)*/;
static final String CFONB_CONFIG_6 = /*$$(*/
"%s : You must configure a CFONB total code register for the company %s" /*)*/;
static final String CFONB_CONFIG_7 = /*$$(*/
"%s : You must configure a CFONB internet payment code for the company %s" /*)*/;
static final String CFONB_CONFIG_8 = /*$$(*/
"%s : You must configure a CFONB direct debit code for the company %s" /*)*/;
static final String CFONB_CONFIG_9 = /*$$(*/
"%s : You must configure a CFONB header code register for the company %s" /*)*/;
static final String CFONB_CONFIG_10 = /*$$(*/
"%s : You must configure a CFONB detail code register for the company %s" /*)*/;
static final String CFONB_CONFIG_11 = /*$$(*/
"%s : You must configure a CFONB code register end for the company %s" /*)*/;
static final String CFONB_CONFIG_12 = /*$$(*/
"%s : You must configure a CFONB rejected direct debit code for the company %s" /*)*/;
static final String CFONB_CONFIG_13 = /*$$(*/
"%s : You must configure a CFONB unpaid direct debit code fir the company %s" /*)*/;
static final String CFONB_CONFIG_14 = /*$$(*/
"%s : You must configure a CFONB unpaid TIP code for the company %s" /*)*/;
static final String CFONB_CONFIG_15 = /*$$(*/
"%s : You must configure a CFONB TIP and cheque TIP code for the company %s" /*)*/;
static final String CFONB_CONFIG_16 = /*$$(*/
"%s : You must configure a CFONB TIP code for the company %s" /*)*/;
/** Payer quality service */
static final String PAYER_QUALITY_1 = /*$$(*/
"%s : Error : You must configure a weight table in general configuration" /*)*/;
/** Debt recovery action service */
static final String DEBT_RECOVERY_ACTION_1 = /*$$(*/ "Debt recovery method missing." /*)*/;
static final String DEBT_RECOVERY_ACTION_2 = /*$$(*/ "Debt recovery line missing." /*)*/;
static final String DEBT_RECOVERY_ACTION_3 = /*$$(*/
"%s : Letter template missing for debt recovery matrix %s (Partner %s, Level %s)." /*)*/;
static final String DEBT_RECOVERY_ACTION_4 = /*$$(*/
"Email is not sent. Please check email account configuration." /*)*/;
/** Debt recovery service */
static final String DEBT_RECOVERY_1 = /*$$(*/ "There's no accounting situation." /*)*/;
static final String DEBT_RECOVERY_2 = /*$$(*/ "Reference date undefined." /*)*/;
static final String DEBT_RECOVERY_3 = /*$$(*/
"Debt recovery method missing for the configuration." /*)*/;
static final String DEBT_RECOVERY_4 = /*$$(*/ "Debt recovery level waiting for approval." /*)*/;
static final String DEBT_RECOVERY_DEBT_RECOVERY_LEVEL_NOT_FOUND = /*$$(*/
"Debt recovery method line not found" /*)*/;
/** Debt recovery session service */
static final String DEBT_RECOVERY_SESSION_1 = /*$$(*/ "Debt recovery method line missing." /*)*/;
/** Invoice batch service */
static final String INVOICE_BATCH_1 = /*$$(*/ "State %s unknown for treatment %s" /*)*/;
/** Invoice generator */
static final String INVOICE_GENERATOR_1 = /*$$(*/ "%s : Invoice's type is not filled %s" /*)*/;
static final String INVOICE_GENERATOR_2 = /*$$(*/ "%s : There's no partner selected" /*)*/;
static final String INVOICE_GENERATOR_3 = /*$$(*/ "%s : Payment condition missing" /*)*/;
static final String INVOICE_GENERATOR_4 = /*$$(*/ "%s : Payment mode missing" /*)*/;
static final String INVOICE_GENERATOR_5 = /*$$(*/ "%s : Invoicing address missing" /*)*/;
static final String INVOICE_GENERATOR_6 = /*$$(*/ "%s : Currency missing" /*)*/;
/** Merge Invoice */
public static final String INVOICE_MERGE_ERROR_CURRENCY = /*$$(*/
"The currency is required and must be the same for all invoices" /*)*/;
public static final String INVOICE_MERGE_ERROR_PARTNER = /*$$(*/
"The partner is required and must be the same for all invoices" /*)*/;
public static final String INVOICE_MERGE_ERROR_COMPANY = /*$$(*/
"The company is required and must be the same for all invoices" /*)*/;
public static final String INVOICE_MERGE_ERROR_SALEORDER = /*$$(*/
"The sale order must be the same for all invoices" /*)*/;
public static final String INVOICE_MERGE_ERROR_PROJECT = /*$$(*/
"The project must be the same for all invoices" /*)*/;
public static final String INVOICE_MASS_PAYMENT_ERROR_PFP_LITIGATION = /*$$(*/
"Their is at least one invoice selected that it is not validated to pay" /*)*/;
/** Invoice line generator */
static final String INVOICE_LINE_GENERATOR_1 = /*$$(*/
"You must select a currency for partner %s (%s)" /*)*/;
static final String INVOICE_LINE_GENERATOR_2 = /*$$(*/
"You must select a currency for company %s" /*)*/;
public static final String INVOICE_LINE_ERROR_FIXED_ASSET_CATEGORY = /*$$(*/
"Fixed asset category is missing on invoice line for product %s" /*)*/;
/** Batch validation */
static final String BATCH_VALIDATION_1 = /*$$(*/ "Invoice validation's reporting :" /*)*/;
static final String BATCH_VALIDATION_2 = /*$$(*/ "Invoice(s) validated" /*)*/;
/** Batch ventilation */
static final String BATCH_VENTILATION_1 = /*$$(*/ "Invoice ventilation's reporting :" /*)*/;
static final String BATCH_VENTILATION_2 = /*$$(*/ "Invoice(s) ventilated" /*)*/;
/** Refund invoice */
static final String REFUND_INVOICE_1 = /*$$(*/
"%s : Payment mode must be filled either in the partner or in the company configuration." /*)*/;
/** Validate state */
static final String INVOICE_VALIDATE_1 = /*$$(*/
"The payment mode is not in adequacy with the invoice type" /*)*/;
static final String INVOICE_VALIDATE_BLOCKING = /*$$(*/
"The partner is blocked for invoicing." /*)*/;
/** Cancel state */
static final String MOVE_CANCEL_1 = /*$$(*/
"Move should be unreconcile before to cancel the invoice" /*)*/;
static final String MOVE_CANCEL_2 = /*$$(*/
"Move is ventilated on a closed period, and can't be canceled" /*)*/;
static final String MOVE_CANCEL_3 = /*$$(*/
"So many accounting operations are used on this move, so move can't be canceled" /*)*/;
static final String INVOICE_CANCEL_1 = /*$$(*/
"Invoice is passed in doubfult debit, and can't be canceled" /*)*/;
static final String INVOICE_PAYMENT_CANCEL = /*$$(*/
"The bank order linked to this invoice payment has already been carried out/rejected, and thus can't be canceled" /*)*/;
/** Ventilate state */
static final String VENTILATE_STATE_1 = /*$$(*/
"Invoice's or credit note's date can't be previous last invoice ventilated's date" /*)*/;
static final String VENTILATE_STATE_2 = /*$$(*/
"Invoice's or credit note's date can't be previous last invoice ventilated on month's date" /*)*/;
static final String VENTILATE_STATE_3 = /*$$(*/
"Invoice's or credit note's date can't be previous last invoice ventilated on year's date" /*)*/;
static final String VENTILATE_STATE_4 = /*$$(*/
"Company %s does not have any invoice's nor credit note's sequence" /*)*/;
static final String VENTILATE_STATE_5 = /*$$(*/
"The partner account can not be determined. Please set up the partner account on the invoice or configure the partner's accounting situation." /*)*/;
static final String VENTILATE_STATE_6 = /*$$(*/
"The account of a product could not be determined or is not filled. Please fill the missing account on invoice line %s" /*)*/;
static final String VENTILATE_STATE_7 = /*$$(*/
"An analytic distribution is set in product but the account used do not allow analytic distribution" /*)*/;
static final String VENTILATE_STATE_FUTURE_DATE = /*$$(*/
"Invoice date can't be in the future." /*)*/;
static final String VENTILATE_STATE_FUTURE_ORIGIN_DATE = /*$$(*/
"Invoice date of origin can't be in the future." /*)*/;
static final String VENTILATE_STATE_MISSING_ORIGIN_DATE = /*$$(*/
"Origin date is missing on the invoice" /*)*/;
/** Workflow ventilation */
String AMOUNT_ADVANCE_PAYMENTS_TOO_HIGH = /*$$(*/
"Sum of advance payments amounts is higher than the total of this invoice." /*)*/;
static final String PAYMENT_AMOUNT_EXCEEDING = /*$$(*/
"%s : Caution - You can't pay for an amount higher than selected invoices" /*)*/;
/** Payment mode service */
static final String PAYMENT_MODE_1 = /*$$(*/ "Associated account not configured" /*)*/;
static final String PAYMENT_MODE_2 = /*$$(*/
"%s : Error : You must configure a sequence for the company %s and a payment mode %s" /*)*/;
static final String PAYMENT_MODE_3 = /*$$(*/
"%s : Error : You must configure a journal for the company %s and a payment mode %s" /*)*/;
/** Payment voucher control service */
static final String PAYMENT_VOUCHER_CONTROL_PAID_AMOUNT = /*$$(*/
"%s : Payment voucher n° %s, the paid amount should be positive" /*)*/;
static final String PAYMENT_VOUCHER_CONTROL_1 = /*$$(*/
"%s : Caution, payment entry nb %s, total line's amount imputed is higher than customer's amount paid." /*)*/;
static final String PAYMENT_VOUCHER_CONTROL_2 = /*$$(*/ "%s : There's no line to pay." /*)*/;
static final String PAYMENT_VOUCHER_CONTROL_3 = /*$$(*/
"%s : You must add a journal and a treasury account into payment mode." /*)*/;
/** Payment voucher load service */
static final String PAYMENT_VOUCHER_LOAD_1 = /*$$(*/ "%s : You must add an amount paid." /*)*/;
/** Payment voucher sequence service */
static final String PAYMENT_VOUCHER_SEQUENCE_1 = /*$$(*/
"%s : You must configure a receipt number (Payment entry) for the company %s" /*)*/;
/** Payment voucher tool service */
static final String PAYMENT_VOUCHER_TOOL_1 = /*$$(*/
"Payment entry's type missing from payment entry %s" /*)*/;
/** Payment schedule line service */
String PAYMENT_SCHEDULE_LINE_NO_DIRECT_DEBIT_PAYMENT_MODE = /*$$(*/
"Missing direct debit payment mode in the company's account configuration" /*)*/;
/** Account chart controller */
static final String ACCOUNT_CHART_1 = /*$$(*/
"The chart of account has been loaded successfully" /*)*/;
static final String ACCOUNT_CHART_2 = /*$$(*/
"Error in account chart import please check the log" /*)*/;
static final String ACCOUNT_CHART_3 = /*$$(*/
"A chart or chart structure of accounts already exists, please delete the hierarchy between accounts in order to import a new chart." /*)*/;
/** Address controller */
static final String ADDRESS_1 = /*$$(*/ "Sales map" /*)*/;
static final String ADDRESS_2 = /*$$(*/ "Not implemented for OSM" /*)*/;
/** Invoice controller */
static final String INVOICE_1 = /*$$(*/ "Invoice canceled" /*)*/;
static final String INVOICE_2 = /*$$(*/ "Credit note created" /*)*/;
static final String INVOICE_3 = /*$$(*/ "Please select the invoice(s) to print." /*)*/;
static final String INVOICE_4 = /*$$(*/ "Refunds from invoice %s" /*)*/;
static final String INVOICE_NO_INVOICE_TO_PAY = /*$$(*/ "No invoice to pay" /*)*/;
/** Move template controller */
static final String MOVE_TEMPLATE_1 = /*$$(*/ "Template move is not balanced" /*)*/;
static final String MOVE_TEMPLATE_2 = /*$$(*/ "Error in move generation" /*)*/;
static final String MOVE_TEMPLATE_3 = /*$$(*/ "Generated moves" /*)*/;
static final String MOVE_TEMPLATE_4 = /*$$(*/ "Please fill input lines" /*)*/;
/** Budget service */
static final String BUDGET_1 = /*$$(*/ "Too much iterations." /*)*/;
static final String USER_PARTNER = /*$$(*/ "You must create a contact for user %s" /*)*/;
/*
* Deposit slip
*/
static final String DEPOSIT_SLIP_MISSING_SEQUENCE = /*$$(*/
"Missing deposit slip sequence for company %s" /*)*/;
static final String DEPOSIT_SLIP_CANNOT_DELETE = /*$$(*/
"You cannot delete this deposit slip." /*)*/;
static final String DEPOSIT_SLIP_ALREADY_PUBLISHED = /*$$(*/
"The deposit slip has already been published." /*)*/;
static final String DEPOSIT_SLIP_UNSUPPORTED_PAYMENT_MODE_TYPE = /*$$(*/
"Unsupported payment mode type" /*)*/;
/*
* Partner
*/
String PARTNER_BANK_DETAILS_MISSING = /*$$(*/ "Bank details are missing for partner %s." /*)*/;
/*
* Invoice printing
*/
String INVOICE_MISSING_PRINTING_SETTINGS = /*$$(*/
"Please fill printing settings on invoice %s." /*)*/;
String INVOICES_MISSING_PRINTING_SETTINGS = /*$$(*/
"Please fill printing settings on following invoices: %s" /*)*/;
String INVOICE_PRINTING_IO_ERROR = /*$$(*/ "Error on uploading printed invoice:" /*)*/;
/*
* Reconcile Group
*/
String RECONCILE_GROUP_VALIDATION_NO_LINES = /*$$(*/
"The reconcile group cannot be validated since there is no lines." /*)*/;
String RECONCILE_GROUP_NO_TEMP_SEQUENCE = /*$$(*/
"There is no configured sequence for temporary reconcile group" /*)*/;
String RECONCILE_GROUP_NO_FINAL_SEQUENCE = /*$$(*/
"There is no configured sequence for final reconcile group" /*)*/;
/*
* Subrogation Release
*/
static final String SUBROGATION_RELEASE_MISSING_SEQUENCE = /*$$(*/
"Missing subrogation release sequence for company %s" /*)*/;
/** MoveLine */
static final String NO_MOVE_LINE_SELECTED = /*$$(*/ "No Lines selected" /*)*/;
/** User */
static final String USER_PFP_VALIDATOR_COMPANY_SET_NOT_EQUAL = /*$$(*/
"%s has not exaclty the same internal companies as %s." /*)*/;
static final String USER_PFP_VALIDATOR_UPDATED = /*$$(*/
"Pfp validator changed successfully" /*)*/;
static final String USER_PFP_VALIDATOR_NO_RELATED_ACCOUNTING_SITUATION = /*$$(*/
"No Accounting Situation related to %s." /*)*/;
/* Check refunds */
String INVOICE_NOT_IMPUTED_CLIENT_REFUNDS = /*$$(*/
"Note: there are existing not imputed client refunds."; /*)*/
String INVOICE_NOT_IMPUTED_SUPPLIER_REFUNDS = /*$$(*/
"Note: there are existing not imputed supplier refunds."; /*)*/
public static final String FIXED_ASSET_DISPOSAL_DATE_ERROR_1 = /*$$(*/
"Disposal date must be after the date of the last depreciation." /*)*/;
public static final String FIXED_ASSET_DISPOSAL_DATE_ERROR_2 = /*$$(*/
"Disposal date shouldn't be after the next planned depreciation date. Please realize all depreciations that happened before the disposal." /*)*/;
/* MOVE REVERSE*/
static final String REVERSE_DATE_SELECT_UNKNOW_TYPE = /*$$(*/
"There is no reverse date select value of value %d" /*)*/;
/*Check not lettered advance move lines*/
public static final String INVOICE_NOT_LETTERED_SUPPLIER_ADVANCE_MOVE_LINES = /*$$(*/
"There is at least one advance payment or payment that can be imputed to this invoice." /*)*/;
static final String CLOSE_NO_REPORTED_BALANCE_DATE = /*$$(*/
"Please set a reported balance date on fiscal year" /*)*/;
String CASH_INVENTORY_MISSING_SEQUENCE = /*$$(*/
"There is no configured sequence for cash inventory" /*)*/;
}

View File

@ -0,0 +1,262 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.module;
import com.axelor.app.AxelorModule;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.repo.AccountAccountRepository;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.apps.account.db.repo.AccountingBatchAccountRepository;
import com.axelor.apps.account.db.repo.AccountingBatchRepository;
import com.axelor.apps.account.db.repo.AccountingReportManagementRepository;
import com.axelor.apps.account.db.repo.AccountingReportRepository;
import com.axelor.apps.account.db.repo.AnalyticMoveLineMngtRepository;
import com.axelor.apps.account.db.repo.AnalyticMoveLineRepository;
import com.axelor.apps.account.db.repo.DepositSlipAccountRepository;
import com.axelor.apps.account.db.repo.DepositSlipRepository;
import com.axelor.apps.account.db.repo.FixedAssetManagementRepository;
import com.axelor.apps.account.db.repo.FixedAssetRepository;
import com.axelor.apps.account.db.repo.InvoiceBatchAccountRepository;
import com.axelor.apps.account.db.repo.InvoiceBatchRepository;
import com.axelor.apps.account.db.repo.InvoiceManagementRepository;
import com.axelor.apps.account.db.repo.InvoicePaymentManagementRepository;
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.db.repo.JournalManagementRepository;
import com.axelor.apps.account.db.repo.JournalRepository;
import com.axelor.apps.account.db.repo.MoveLineManagementRepository;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveManagementRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.PartnerAccountRepository;
import com.axelor.apps.account.db.repo.PaymentVoucherManagementRepository;
import com.axelor.apps.account.db.repo.PaymentVoucherRepository;
import com.axelor.apps.account.db.repo.ReconcileGroupAccountRepository;
import com.axelor.apps.account.db.repo.ReconcileGroupRepository;
import com.axelor.apps.account.db.repo.ReconcileManagementRepository;
import com.axelor.apps.account.db.repo.ReconcileRepository;
import com.axelor.apps.account.db.repo.SubrogationReleaseManagementRepository;
import com.axelor.apps.account.db.repo.SubrogationReleaseRepository;
import com.axelor.apps.account.service.AccountManagementAccountService;
import com.axelor.apps.account.service.AccountManagementServiceAccountImpl;
import com.axelor.apps.account.service.AccountingCloseAnnualService;
import com.axelor.apps.account.service.AccountingCloseAnnualServiceImpl;
import com.axelor.apps.account.service.AccountingReportService;
import com.axelor.apps.account.service.AccountingReportServiceImpl;
import com.axelor.apps.account.service.AccountingSituationService;
import com.axelor.apps.account.service.AccountingSituationServiceImpl;
import com.axelor.apps.account.service.AddressServiceAccountImpl;
import com.axelor.apps.account.service.AnalyticMoveLineService;
import com.axelor.apps.account.service.AnalyticMoveLineServiceImpl;
import com.axelor.apps.account.service.BankDetailsServiceAccountImpl;
import com.axelor.apps.account.service.DepositSlipService;
import com.axelor.apps.account.service.DepositSlipServiceImpl;
import com.axelor.apps.account.service.FiscalPositionAccountService;
import com.axelor.apps.account.service.FiscalPositionAccountServiceImpl;
import com.axelor.apps.account.service.FixedAssetLineService;
import com.axelor.apps.account.service.FixedAssetLineServiceImpl;
import com.axelor.apps.account.service.FixedAssetService;
import com.axelor.apps.account.service.FixedAssetServiceImpl;
import com.axelor.apps.account.service.MoveLineExportService;
import com.axelor.apps.account.service.MoveLineExportServiceImpl;
import com.axelor.apps.account.service.NotificationService;
import com.axelor.apps.account.service.NotificationServiceImpl;
import com.axelor.apps.account.service.PaymentScheduleLineService;
import com.axelor.apps.account.service.PaymentScheduleLineServiceImpl;
import com.axelor.apps.account.service.PaymentScheduleService;
import com.axelor.apps.account.service.PaymentScheduleServiceImpl;
import com.axelor.apps.account.service.PeriodServiceAccount;
import com.axelor.apps.account.service.PeriodServiceAccountImpl;
import com.axelor.apps.account.service.ReconcileGroupSequenceService;
import com.axelor.apps.account.service.ReconcileGroupSequenceServiceImpl;
import com.axelor.apps.account.service.ReconcileGroupService;
import com.axelor.apps.account.service.ReconcileGroupServiceImpl;
import com.axelor.apps.account.service.ReconcileService;
import com.axelor.apps.account.service.ReconcileServiceImpl;
import com.axelor.apps.account.service.SubrogationReleaseService;
import com.axelor.apps.account.service.SubrogationReleaseServiceImpl;
import com.axelor.apps.account.service.TaxPaymentMoveLineService;
import com.axelor.apps.account.service.TaxPaymentMoveLineServiceImpl;
import com.axelor.apps.account.service.TemplateMessageAccountService;
import com.axelor.apps.account.service.TemplateMessageAccountServiceImpl;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.app.AppAccountServiceImpl;
import com.axelor.apps.account.service.extract.ExtractContextMoveService;
import com.axelor.apps.account.service.extract.ExtractContextMoveServiceImpl;
import com.axelor.apps.account.service.invoice.InvoiceLineService;
import com.axelor.apps.account.service.invoice.InvoiceLineServiceImpl;
import com.axelor.apps.account.service.invoice.InvoiceService;
import com.axelor.apps.account.service.invoice.InvoiceServiceImpl;
import com.axelor.apps.account.service.invoice.print.InvoicePrintService;
import com.axelor.apps.account.service.invoice.print.InvoicePrintServiceImpl;
import com.axelor.apps.account.service.invoice.workflow.cancel.WorkflowCancelService;
import com.axelor.apps.account.service.invoice.workflow.cancel.WorkflowCancelServiceImpl;
import com.axelor.apps.account.service.invoice.workflow.validate.WorkflowValidationService;
import com.axelor.apps.account.service.invoice.workflow.validate.WorkflowValidationServiceImpl;
import com.axelor.apps.account.service.invoice.workflow.ventilate.WorkflowVentilationService;
import com.axelor.apps.account.service.invoice.workflow.ventilate.WorkflowVentilationServiceImpl;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.account.service.move.MoveServiceImpl;
import com.axelor.apps.account.service.payment.PaymentModeService;
import com.axelor.apps.account.service.payment.PaymentModeServiceImpl;
import com.axelor.apps.account.service.payment.PaymentService;
import com.axelor.apps.account.service.payment.PaymentServiceImpl;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCancelService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCancelServiceImpl;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateServiceImpl;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentToolService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentToolServiceImpl;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentValidateService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentValidateServiceImpl;
import com.axelor.apps.account.service.umr.UmrNumberService;
import com.axelor.apps.account.service.umr.UmrNumberServiceImpl;
import com.axelor.apps.base.db.repo.PartnerAddressRepository;
import com.axelor.apps.base.db.repo.PartnerBaseRepository;
import com.axelor.apps.base.service.BankDetailsServiceImpl;
import com.axelor.apps.base.service.PeriodServiceImpl;
import com.axelor.apps.base.service.tax.AccountManagementServiceImpl;
import com.axelor.apps.base.service.tax.FiscalPositionServiceImpl;
import com.axelor.apps.message.service.TemplateMessageService;
import com.axelor.apps.message.service.TemplateMessageServiceImpl;
public class AccountModule extends AxelorModule {
@Override
protected void configure() {
bind(AddressServiceAccountImpl.class);
bind(AccountManagementServiceImpl.class).to(AccountManagementServiceAccountImpl.class);
bind(AccountManagementAccountService.class).to(AccountManagementServiceAccountImpl.class);
bind(FiscalPositionServiceImpl.class).to(FiscalPositionAccountServiceImpl.class);
bind(FiscalPositionAccountService.class).to(FiscalPositionAccountServiceImpl.class);
bind(TemplateMessageService.class).to(TemplateMessageServiceImpl.class);
bind(InvoiceRepository.class).to(InvoiceManagementRepository.class);
bind(MoveRepository.class).to(MoveManagementRepository.class);
bind(MoveLineRepository.class).to(MoveLineManagementRepository.class);
bind(AccountingReportRepository.class).to(AccountingReportManagementRepository.class);
bind(AccountingReportService.class).to(AccountingReportServiceImpl.class);
bind(JournalRepository.class).to(JournalManagementRepository.class);
bind(PaymentVoucherRepository.class).to(PaymentVoucherManagementRepository.class);
bind(InvoiceService.class).to(InvoiceServiceImpl.class);
bind(InvoicePrintService.class).to(InvoicePrintServiceImpl.class);
bind(PartnerBaseRepository.class).to(PartnerAccountRepository.class);
bind(AnalyticMoveLineService.class).to(AnalyticMoveLineServiceImpl.class);
bind(InvoicePaymentRepository.class).to(InvoicePaymentManagementRepository.class);
bind(InvoicePaymentValidateService.class).to(InvoicePaymentValidateServiceImpl.class);
bind(InvoicePaymentCreateService.class).to(InvoicePaymentCreateServiceImpl.class);
bind(InvoicePaymentCancelService.class).to(InvoicePaymentCancelServiceImpl.class);
bind(InvoicePaymentToolService.class).to(InvoicePaymentToolServiceImpl.class);
bind(AnalyticMoveLineRepository.class).to(AnalyticMoveLineMngtRepository.class);
bind(ReconcileService.class).to(ReconcileServiceImpl.class);
bind(ReconcileRepository.class).to(ReconcileManagementRepository.class);
bind(AppAccountService.class).to(AppAccountServiceImpl.class);
bind(AccountingSituationService.class).to(AccountingSituationServiceImpl.class);
bind(PaymentModeService.class).to(PaymentModeServiceImpl.class);
bind(BankDetailsServiceImpl.class).to(BankDetailsServiceAccountImpl.class);
bind(MoveLineExportService.class).to(MoveLineExportServiceImpl.class);
bind(AccountingBatchRepository.class).to(AccountingBatchAccountRepository.class);
bind(InvoiceBatchRepository.class).to(InvoiceBatchAccountRepository.class);
bind(AccountRepository.class).to(AccountAccountRepository.class);
bind(WorkflowVentilationService.class).to(WorkflowVentilationServiceImpl.class);
bind(WorkflowCancelService.class).to(WorkflowCancelServiceImpl.class);
bind(WorkflowValidationService.class).to(WorkflowValidationServiceImpl.class);
bind(SubrogationReleaseService.class).to(SubrogationReleaseServiceImpl.class);
bind(NotificationService.class).to(NotificationServiceImpl.class);
bind(PaymentScheduleService.class).to(PaymentScheduleServiceImpl.class);
bind(PaymentScheduleLineService.class).to(PaymentScheduleLineServiceImpl.class);
bind(DepositSlipRepository.class).to(DepositSlipAccountRepository.class);
bind(DepositSlipService.class).to(DepositSlipServiceImpl.class);
bind(InvoiceLineService.class).to(InvoiceLineServiceImpl.class);
bind(TemplateMessageAccountService.class).to(TemplateMessageAccountServiceImpl.class);
PartnerAddressRepository.modelPartnerFieldMap.put(Invoice.class.getName(), "partner");
bind(UmrNumberService.class).to(UmrNumberServiceImpl.class);
bind(ReconcileGroupSequenceService.class).to(ReconcileGroupSequenceServiceImpl.class);
bind(ReconcileGroupRepository.class).to(ReconcileGroupAccountRepository.class);
bind(ReconcileGroupService.class).to(ReconcileGroupServiceImpl.class);
bind(SubrogationReleaseRepository.class).to(SubrogationReleaseManagementRepository.class);
bind(PeriodServiceImpl.class).to(PeriodServiceAccountImpl.class);
bind(FixedAssetRepository.class).to(FixedAssetManagementRepository.class);
bind(FixedAssetService.class).to(FixedAssetServiceImpl.class);
bind(FixedAssetLineService.class).to(FixedAssetLineServiceImpl.class);
bind(ExtractContextMoveService.class).to(ExtractContextMoveServiceImpl.class);
bind(AccountingCloseAnnualService.class).to(AccountingCloseAnnualServiceImpl.class);
bind(PeriodServiceAccount.class).to(PeriodServiceAccountImpl.class);
bind(MoveService.class).to(MoveServiceImpl.class);
bind(TaxPaymentMoveLineService.class).to(TaxPaymentMoveLineServiceImpl.class);
bind(PaymentService.class).to(PaymentServiceImpl.class);
}
}

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.account.report;
public interface IReport {
public static final String ACCOUNTING_REPORT_TYPE = "AccountingReportType%s.rptdesign";
public static final String PAYMENT_VOUCHER = "PaymentVoucher.rptdesign";
public static final String IRRECOVERABLE = "Irrecoverable.rptdesign";
public static final String INVOICE = "Invoice.rptdesign";
public static final String SALE_INVOICES_DETAILS = "SaleInvoicesDetails.rptdesign";
public static final String PURCHASE_INVOICES_DETAILS = "PurchaseInvoicesDetails.rptdesign";
public static final String ACCOUNT_MOVE = "AccountMove.rptdesign";
public static final String SUBROGATION_RELEASE = "SubrogationRelease.rptdesign";
public static final String CHEQUE_DEPOSIT_SLIP = "ChequeDepositSlip.rptdesign";
public static final String CASH_DEPOSIT_SLIP = "CashDepositSlip.rptdesign";
public static final String CASH_INVENTORY = "CashInventory%s.rptdesign";
}

View File

@ -0,0 +1,510 @@
/*
* 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.account.report;
public interface ITranslation {
public static final String INVOICE_ADVANCE_PAYMENTS = /*$$(*/ "Invoice.advancePayments"; /*)*/
public static final String INVOICE_DATE = /*$$(*/ "Invoice.date"; /*)*/
public static final String INVOICE_PAYMENT_TERMS = /*$$(*/ "Invoice.paymentTerms"; /*)*/
public static final String INVOICE_DUE_DATE = /*$$(*/ "Invoice.dueDate"; /*)*/
public static final String INVOICE_DOCUMENT_REF = /*$$(*/ "Invoice.documentRef"; /*)*/
public static final String INVOICE_SUPPLIER = /*$$(*/ "Invoice.supplier"; /*)*/
public static final String INVOICE_DESCRIPTION = /*$$(*/ "Invoice.description"; /*)*/
public static final String INVOICE_TAX = /*$$(*/ "Invoice.tax"; /*)*/
public static final String INVOICE_QTY_UNIT = /*$$(*/ "Invoice.qtyUnit"; /*)*/
public static final String INVOICE_UNIT_PRICE = /*$$(*/ "Invoice.unitPrice"; /*)*/
public static final String INVOICE_PRICE_EXCL_TAX = /*$$(*/ "Invoice.priceExclTax"; /*)*/
public static final String INVOICE_PRICE_INCL_TAX = /*$$(*/ "Invoice.priceInclTax"; /*)*/
public static final String INVOICE_BASE = /*$$(*/ "Invoice.base"; /*)*/
public static final String INVOICE_TAX_AMOUNT = /*$$(*/ "Invoice.taxAmount"; /*)*/
public static final String INVOICE_TOTAL_EXCL_TAX = /*$$(*/ "Invoice.totalExclTax"; /*)*/
public static final String INVOICE_TOTAL_EXCL_TAX_WITHOUT_DISCOUNT = /*$$(*/
"Invoice.totalExclTaxWithoutDiscount"; /*)*/
public static final String INVOICE_TOTAL_TAX = /*$$(*/ "Invoice.totalTax"; /*)*/
public static final String INVOICE_TOTAL_INCL_TAX = /*$$(*/ "Invoice.totalInclTax"; /*)*/
public static final String INVOICE_TOTAL_DISCOUNT = /*$$(*/ "Invoice.totalDiscount"; /*)*/
public static final String INVOICE_AFTER_DISCOUNT = /*$$(*/ "Invoice.afterDiscount"; /*)*/
public static final String INVOICE_NOTE = /*$$(*/ "Invoice.note"; /*)*/
public static final String INVOICE_CHEQUE = /*$$(*/ "Invoice.cheque"; /*)*/
public static final String INVOICE_BANK_DETAILS = /*$$(*/ "Invoice.bankDetails"; /*)*/
public static final String INVOICE_BANKING_INFO = /*$$(*/ "Invoice.bankingInfo"; /*)*/
public static final String INVOICE_CLIENT_REF = /*$$(*/ "Invoice.clientRef"; /*)*/
public static final String INVOICE_SUPPLY_REF = /*$$(*/ "Invoice.supplyRef"; /*)*/
public static final String INVOICE_PURCHASE_INVOICE_NO = /*$$(*/
"Invoice.purchaseInvoiceNo"; /*)*/
public static final String INVOICE_PURCHASE_INVOICE_ADV_PAYMENT_NO = /*$$(*/
"Invoice.purchaseInvoiceAdvPaymentNo"; /*)*/
public static final String INVOICE_PURCHASE_INVOICE_BALANCE_NO = /*$$(*/
"Invoice.purchaseInvoiceBalanceNo"; /*)*/
public static final String INVOICE_PURCHASE_REFUND_NO = /*$$(*/ "Invoice.purchaseRefundNo"; /*)*/
public static final String INVOICE_INVOICE_NO = /*$$(*/ "Invoice.invoiceNo"; /*)*/
public static final String INVOICE_INVOICE_ADV_PAYMENT_NO = /*$$(*/
"Invoice.invoiceAdvPaymentNo"; /*)*/
public static final String INVOICE_INVOICE_BALANCE_NO = /*$$(*/ "Invoice.invoiceBalanceNo"; /*)*/
public static final String INVOICE_DRAFT_INVOICE_NO = /*$$(*/ "Invoice.draftInvoiceNo"; /*)*/
public static final String INVOICE_REFUND_NO = /*$$(*/ "Invoice.refundNo"; /*)*/
public static final String INVOICE_DISCOUNT_AMOUNT = /*$$(*/ "Invoice.discountAmount"; /*)*/
public static final String INVOICE_ADVANCE_PAYMENT = /*$$(*/ "Invoice.advancePayment"; /*)*/
public static final String INVOICE_OF = /*$$(*/ "Invoice.of"; /*)*/
public static final String INVOICE_IMPUTED_ON = /*$$(*/ "Invoice.imputedOn"; /*)*/
public static final String INVOICE_TOTAL_TO_PAY = /*$$(*/ "Invoice.totalToPay"; /*)*/
public static final String INVOICE_CANCEL_INVOICE_NO = /*$$(*/ "Invoice.cancelInvoiceNo"; /*)*/
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_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 INVOICE_PRODUCT_CODE = /*$$(*/ "Invoice.productCode"; /*)*/
public static final String INVOICE_TERMS_AND_CONDITIONS = /*$$(*/
"Invoice.termsAndConditions"; /*)*/
public static final String INVOICE_SUBSCRIPTION_PERIOD = /*$$(*/
"Invoice.subscriptionPeriod"; /*)*/
public static final String INVOICE_CUSTOMER_PARTNER_SEQ = /*$$(*/
"Invoice.customerPartnerSeq"; /*)*/
public static final String INVOICE_SUPPLIER_PARTNER_SEQ = /*$$(*/
"Invoice.supplierPartnerSeq"; /*)*/
public static final String INVOICE_CUSTOMER_TAX_NUMBER = /*$$(*/
"Invoice.customerTaxNumber"; /*)*/
public static final String INVOICE_AMOUNT_REMAINING = /*$$(*/ "Invoice.amountRemaining"; /*)*/
public static final String INVOICE_PROFORMA_INVOICE = /*$$(*/ "Invoice.proformaInvoice"; /*)*/
public static final String ACCOUNTING_REPORT_EDITION_DATE = /*$$(*/
"AccountingReport.editionDate"; /*)*/
public static final String ACCOUNTING_REPORT_RECAP_BY_ACCOUNT = /*$$(*/
"AccountingReport.recapByAccount"; /*)*/
public static final String ACCOUNTING_REPORT_TOTAL_DEBIT_ACCOUNT = /*$$(*/
"AccountingReport.totalDebitAccount"; /*)*/
public static final String ACCOUNTING_REPORT_TOTAL_CREDIT_ACCOUNT = /*$$(*/
"AccountingReport.totalCreditAccount"; /*)*/
public static final String ACCOUNTING_REPORT_CONTROL = /*$$(*/ "AccountingReport.control"; /*)*/
public static final String ACCOUNTING_REPORT_1_TITLE = /*$$(*/
"AccountingReportType1.title"; /*)*/
public static final String ACCOUNTING_REPORT_1_JOURNAL = /*$$(*/
"AccountingReportType1.journal"; /*)*/
public static final String ACCOUNTING_REPORT_1_COMPANY = /*$$(*/
"AccountingReportType1.company"; /*)*/
public static final String ACCOUNTING_REPORT_1_END_DATE = /*$$(*/
"AccountingReportType1.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_1_FROM = /*$$(*/ "AccountingReportType1.from"; /*)*/
public static final String ACCOUNTING_REPORT_1_TO = /*$$(*/ "AccountingReportType1.to"; /*)*/
public static final String ACCOUNTING_REPORT_1_PERIOD = /*$$(*/
"AccountingReportType1.period"; /*)*/
public static final String ACCOUNTING_REPORT_1_PAYMENT_MODE = /*$$(*/
"AccountingReportType1.paymentMode"; /*)*/
public static final String ACCOUNTING_REPORT_1_DATE = /*$$(*/ "AccountingReportType1.date"; /*)*/
public static final String ACCOUNTING_REPORT_1_CODE = /*$$(*/ "AccountingReportType1.code"; /*)*/
public static final String ACCOUNTING_REPORT_1_NAME = /*$$(*/ "AccountingReportType1.name"; /*)*/
public static final String ACCOUNTING_REPORT_1_DESCRIPTION = /*$$(*/
"AccountingReportType1.description"; /*)*/
public static final String ACCOUNTING_REPORT_1_PARTNER = /*$$(*/
"AccountingReportType1.partner"; /*)*/
public static final String ACCOUNTING_REPORT_1_BALANCE = /*$$(*/
"AccountingReportType1.balance"; /*)*/
public static final String ACCOUNTING_REPORT_1_DEBIT = /*$$(*/
"AccountingReportType1.debit"; /*)*/
public static final String ACCOUNTING_REPORT_1_CREDIT = /*$$(*/
"AccountingReportType1.credit"; /*)*/
public static final String ACCOUNTING_REPORT_1_TOTAL = /*$$(*/
"AccountingReportType1.total"; /*)*/
public static final String ACCOUNTING_REPORT_7_TITLE = /*$$(*/
"AccountingReportType7.title"; /*)*/
public static final String ACCOUNTING_REPORT_7_DUE_DATE = /*$$(*/
"AccountingReportType7.dueDate"; /*)*/
public static final String ACCOUNTING_REPORT_7_RECONCILE_GROUP = /*$$(*/
"AccountingReportType7.reconcileGroup"; /*)*/
public static final String ACCOUNTING_REPORT_7_JOURNAL_DATE = /*$$(*/
"AccountingReportType7.journalCode"; /*)*/
public static final String ACCOUNTING_REPORT_7_JOURNAL = /*$$(*/
"AccountingReportType1.journal"; /*)*/
public static final String ACCOUNTING_REPORT_7_COMPANY = /*$$(*/
"AccountingReportType1.company"; /*)*/
public static final String ACCOUNTING_REPORT_7_END_DATE = /*$$(*/
"AccountingReportType1.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_7_FROM = /*$$(*/ "AccountingReportType1.from"; /*)*/
public static final String ACCOUNTING_REPORT_7_TO = /*$$(*/ "AccountingReportType1.to"; /*)*/
public static final String ACCOUNTING_REPORT_7_PERIOD = /*$$(*/
"AccountingReportType1.period"; /*)*/
public static final String ACCOUNTING_REPORT_7_PAYMENT_MODE = /*$$(*/
"AccountingReportType1.paymentMode"; /*)*/
public static final String ACCOUNTING_REPORT_7_DATE = /*$$(*/ "AccountingReportType1.date"; /*)*/
public static final String ACCOUNTING_REPORT_7_DESCRIPTION = /*$$(*/
"AccountingReportType1.description"; /*)*/
public static final String ACCOUNTING_REPORT_7_PARTNER = /*$$(*/
"AccountingReportType1.partner"; /*)*/
public static final String ACCOUNTING_REPORT_7_BALANCE = /*$$(*/
"AccountingReportType1.balance"; /*)*/
public static final String ACCOUNTING_REPORT_7_DEBIT = /*$$(*/
"AccountingReportType1.debit"; /*)*/
public static final String ACCOUNTING_REPORT_7_CREDIT = /*$$(*/
"AccountingReportType1.credit"; /*)*/
public static final String ACCOUNTING_REPORT_7_TOTAL = /*$$(*/
"AccountingReportType1.total"; /*)*/
public static final String ACCOUNTING_REPORT_2_TITLE = /*$$(*/
"AccountingReportType2.title"; /*)*/
public static final String ACCOUNTING_REPORT_2_JOURNAL = /*$$(*/
"AccountingReportType2.journal"; /*)*/
public static final String ACCOUNTING_REPORT_2_COMPANY = /*$$(*/
"AccountingReportType2.company"; /*)*/
public static final String ACCOUNTING_REPORT_2_END_DATE = /*$$(*/
"AccountingReportType2.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_2_FROM = /*$$(*/ "AccountingReportType2.from"; /*)*/
public static final String ACCOUNTING_REPORT_2_TO = /*$$(*/ "AccountingReportType2.to"; /*)*/
public static final String ACCOUNTING_REPORT_2_PERIOD = /*$$(*/
"AccountingReportType2.period"; /*)*/
public static final String ACCOUNTING_REPORT_2_PAYMENT_MODE = /*$$(*/
"AccountingReportType2.paymentMode"; /*)*/
public static final String ACCOUNTING_REPORT_2_ACCOUNT = /*$$(*/
"AccountingReportType2.account"; /*)*/
public static final String ACCOUNTING_REPORT_2_ACCOUNT_LABEL = /*$$(*/
"AccountingReportType2.accountLabel"; /*)*/
public static final String ACCOUNTING_REPORT_2_TOTAL_DEBIT = /*$$(*/
"AccountingReportType2.totalDebit"; /*)*/
public static final String ACCOUNTING_REPORT_2_TOTAL_CREDIT = /*$$(*/
"AccountingReportType2.totalCredit"; /*)*/
public static final String ACCOUNTING_REPORT_2_BALANCE = /*$$(*/
"AccountingReportType2.balance"; /*)*/
public static final String ACCOUNTING_REPORT_2_DEBIT = /*$$(*/
"AccountingReportType2.debit"; /*)*/
public static final String ACCOUNTING_REPORT_2_CREDIT = /*$$(*/
"AccountingReportType2.credit"; /*)*/
public static final String ACCOUNTING_REPORT_2_GENERAL_BALANCE = /*$$(*/
"AccountingReportType2.generalBalance"; /*)*/
public static final String ACCOUNTING_REPORT_6_TITLE = /*$$(*/
"AccountingReportType6.title"; /*)*/
public static final String ACCOUNTING_REPORT_15_TITLE = /*$$(*/
"AccountingReportType15.title"; /*)*/
public static final String ACCOUNTING_REPORT_15_COMPANY = /*$$(*/
"AccountingReportType15.company"; /*)*/
public static final String ACCOUNTING_REPORT_15_FROM = /*$$(*/
"AccountingReportType15.from"; /*)*/
public static final String ACCOUNTING_REPORT_15_TO = /*$$(*/ "AccountingReportType15.to"; /*)*/
public static final String ACCOUNTING_REPORT_15_YEAR = /*$$(*/
"AccountingReportType15.year"; /*)*/
public static final String ACCOUNTING_REPORT_15_VAT_TOTAL = /*$$(*/
"AccountingReportType15.vatTotal"; /*)*/
public static final String ACCOUNTING_REPORT_15_PRINT_DATE = /*$$(*/
"AccountingReportType15.printDate"; /*)*/
public static final String ACCOUNTING_REPORT_15_CURRENCY = /*$$(*/
"AccountingReportType15.currency"; /*)*/
public static final String ACCOUNTING_REPORT_15_TAX_CODE = /*$$(*/
"AccountingReportType15.taxCode"; /*)*/
public static final String ACCOUNTING_REPORT_15_NAME = /*$$(*/
"AccountingReportType15.name"; /*)*/
public static final String ACCOUNTING_REPORT_15_MOVE_LINE = /*$$(*/
"AccountingReportType15.moveLine"; /*)*/
public static final String ACCOUNTING_REPORT_15_DATE = /*$$(*/
"AccountingReportType15.date"; /*)*/
public static final String ACCOUNTING_REPORT_15_MOVE_LINE_ACCOUNT = /*$$(*/
"AccountingReportType15.moveLineAccount"; /*)*/
public static final String ACCOUNTING_REPORT_15_ACCOUNT_NAME = /*$$(*/
"AccountingReportType15.accountName"; /*)*/
public static final String ACCOUNTING_REPORT_15_BASE = /*$$(*/
"AccountingReportType15.base"; /*)*/
public static final String ACCOUNTING_REPORT_15_VAT_CASH_ACCOUNTING_SCHEME = /*$$(*/
"AccountingReportType15.vatCashAccountingScheme"; /*)*/
public static final String ACCOUNTING_REPORT_15_PAYABLE_VAT = /*$$(*/
"AccountingReportType15.payableVAT"; /*)*/
public static final String ACCOUNTING_REPORT_15_DEDUCTIBLE_VAT = /*$$(*/
"AccountingReportType15.deductibleVAT"; /*)*/
public static final String ACCOUNTING_REPORT_15_REPORT_DATE_EDITION = /*$$(*/
"AccountingReportType15.reportDateEdition"; /*)*/
public static final String ACCOUNTING_REPORT_15_TOTAL = /*$$(*/
"AccountingReportType15.total"; /*)*/
public static final String ACCOUNTING_REPORT_15_BLANCE = /*$$(*/
"AccountingReportType15.balance"; /*)*/
public static final String ACCOUNTING_REPORT_15_AMOUNT = /*$$(*/
"AccountingReportType15.amount"; /*)*/
public static final String ACCOUNTING_REPORT_15_TAX_RATE = /*$$(*/
"AccountingReportType15.taxRate"; /*)*/
public static final String ACCOUNTING_REPORT_11_JOURNAL = /*$$(*/
"AccountingReportType11.daySubTotal"; /*)*/
public static final String ACCOUNTING_REPORT_2000_TITLE = /*$$(*/
"AccountingReportType2000.title"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_JOURNAL = /*$$(*/
"AccountingReportType2000.analyticJournal"; /*)*/
public static final String ACCOUNTING_REPORT_2000_COMPANY = /*$$(*/
"AccountingReportType2000.company"; /*)*/
public static final String ACCOUNTING_REPORT_2000_END_DATE = /*$$(*/
"AccountingReportType2000.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_2000_FROM = /*$$(*/
"AccountingReportType2000.from"; /*)*/
public static final String ACCOUNTING_REPORT_2000_TO = /*$$(*/
"AccountingReportType2000.to"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_AXIS = /*$$(*/
"AccountingReportType2000.analyticAxis"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_AXIS_CODE = /*$$(*/
"AccountingReportType2000.analyticAxisCode"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_AXIS_NAME = /*$$(*/
"AccountingReportType2000.analyticAxisName"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_ACCOUNT = /*$$(*/
"AccountingReportType2000.analyticAccount"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_ACCOUNT_CODE = /*$$(*/
"AccountingReportType2000.analyticAccountCode"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ANALYTIC_ACCOUNT_NAME = /*$$(*/
"AccountingReportType2000.analyticAccountName"; /*)*/
public static final String ACCOUNTING_REPORT_2000_ACCOUNT_TYPE = /*$$(*/
"AccountingReportType2000.accountType"; /*)*/
public static final String ACCOUNTING_REPORT_2000_AMOUNT = /*$$(*/
"AccountingReportType2000.amount"; /*)*/
public static final String ACCOUNTING_REPORT_2000_PERCENTAGE = /*$$(*/
"AccountingReportType2000.percentage"; /*)*/
public static final String ACCOUNTING_REPORT_2000_TOTAL_PER_ANALYTIC_JOURNAL = /*$$(*/
"AccountingReportType2000.totalPerAnalyticJournal"; /*)*/
public static final String ACCOUNTING_REPORT_2000_TOTAL_PER_ANALYTIC_AXIS = /*$$(*/
"AccountingReportType2000.totalPerAnalyticAxis"; /*)*/
public static final String ACCOUNTING_REPORT_2000_TOTAL_PER_ANALYTIC_ACCOUNT = /*$$(*/
"AccountingReportType2000.totalPerAnalyticAccount"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_TITLE = /*$$(*/
"SaleInvoicesDetails.title"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_COMPANY = /*$$(*/
"SaleInvoicesDetails.company"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_PUBLICATION_DATE = /*$$(*/
"SaleInvoicesDetails.publicationDate"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_PRODUCT_CATEGORIES = /*$$(*/
"SaleInvoicesDetails.productCategories"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_INVOICED = /*$$(*/
"SaleInvoicesDetails.invoiced"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_ORDERED = /*$$(*/
"SaleInvoicesDetails.ordered"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_SUBTOTAL = /*$$(*/
"SaleInvoicesDetails.subtotal"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_SUM_BY_PARTNER = /*$$(*/
"SaleInvoicesDetails.sumByPartner"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_SUM_BY_PRODUCT = /*$$(*/
"SaleInvoicesDetails.sumByProduct"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_TOTAL_ORDER = /*$$(*/
"SaleInvoicesDetails.totalOrder"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_TOTAL_INVOICE = /*$$(*/
"SaleInvoicesDetails.totalInvoice"; /*)*/
public static final String SALE_INVOICE_DETAILS_REPORT_TOTAL_TURNOVER = /*$$(*/
"SaleInvoicesDetails.totalTurnover"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_TITLE = /*$$(*/
"PurchaseInvoicesDetails.title"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_COMPANY = /*$$(*/
"PurchaseInvoicesDetails.company"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_PUBLICATION_DATE = /*$$(*/
"PurchaseInvoicesDetails.publicationDate"; /*)*/
public static final String PURCHASE_INVOICE_ETAILS_REPORT_PRODUCT_CATEGORIES = /*$$(*/
"PurchaseInvoicesDetails.productCategories"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_INVOICED = /*$$(*/
"PurchaseInvoicesDetails.invoiced"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_ORDERED = /*$$(*/
"PurchaseInvoicesDetails.ordered"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_SUBTOTAL = /*$$(*/
"PurchaseInvoicesDetails.subtotal"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_SUM_BY_PARTNER = /*$$(*/
"PurchaseInvoicesDetails.sumByPartner"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_SUM_BY_PRODUCT = /*$$(*/
"PurchaseInvoicesDetails.sumByProduct"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_TOTAL_ORDER = /*$$(*/
"PurchaseInvoicesDetails.totalOrder"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_TOTAL_INVOICE = /*$$(*/
"PurchaseInvoicesDetails.totalInvoice"; /*)*/
public static final String PURCHASE_INVOICE_DETAILS_REPORT_TOTAL_TURNOVER = /*$$(*/
"PurchaseInvoicesDetails.totalTurnover"; /*)*/
public static final String ACCOUNT_MOVE_TITLE = /*$$(*/ "move.title"; /*)*/
public static final String ACCOUNT_MOVE_REFERENCE = /*$$(*/ "move.reference"; /*)*/
public static final String ACCOUNT_MOVE_JOURNAL = /*$$(*/ "move.journal"; /*)*/
public static final String ACCOUNT_MOVE_PARTNER = /*$$(*/ "move.partner"; /*)*/
public static final String ACCOUNT_MOVE_TECHNICAL_ORIGIN = /*$$(*/ "move.technical.origin"; /*)*/
public static final String ACCOUNT_MOVE_PERIOD = /*$$(*/ "move.period"; /*)*/
public static final String ACCOUNT_MOVE_CURRENCY = /*$$(*/ "move.currency"; /*)*/
public static final String ACCOUNT_MOVE_COMPANY = /*$$(*/ "move.company"; /*)*/
public static final String ACCOUNT_MOVE_LINE_DATE = /*$$(*/ "moveLine.date"; /*)*/
public static final String ACCOUNT_MOVE_LINE_PARTNER = /*$$(*/ "moveLine.partner"; /*)*/
public static final String ACCOUNT_MOVE_LINE_ACCOUNT = /*$$(*/ "moveLine.account"; /*)*/
public static final String ACCOUNT_MOVE_LINE_DEBIT = /*$$(*/ "moveLine.debit"; /*)*/
public static final String ACCOUNT_MOVE_LINE_CREDIT = /*$$(*/ "moveLine.credit"; /*)*/
public static final String ACCOUNT_MOVE_LINE_CURRENCY_AMOUNT = /*$$(*/
"moveLine.currency.amount"; /*)*/
public static final String ACCOUNT_MOVE_LINE_TAX_RATE = /*$$(*/ "moveLine.tax.rate"; /*)*/
public static final String ACCOUNT_MOVE_LINE_RECONCILE_LIST = /*$$(*/
"moveLine.reconcile.list"; /*)*/
public static final String ACCOUNT_MOVE_LINE_DESC = /*$$(*/ "moveLine.description"; /*)*/
public static final String ACCOUNT_MOVE_LINE_ORIGIN = /*$$(*/ "moveLine.origin"; /*)*/
public static final String ACCOUNT_MOVE_LINE_RECONCILE_GROUP = /*$$(*/
"moveLine.reconcileGroup"; /*)*/
public static final String ACCOUNT_MOVE_LINE_TOTAL_LINES = /*$$(*/ "moveLine.totalLines"; /*)*/
public static final String ACCOUNT_MOVE_LINE_TOTAL_DEBIT = /*$$(*/ "moveLine.totalDebit"; /*)*/
public static final String ACCOUNT_MOVE_LINE_TOTAL_CREDIT = /*$$(*/ "moveLine.totalCredit"; /*)*/
public static final String ACCOUNT_MOVE_LINE_DIFFERENCE = /*$$(*/ "moveLine.difference"; /*)*/
public static final String SUBROGATION_RELEASE_TITLE = /*$$(*/ "SubrogationRelease.title"; /*)*/
public static final String SUBROGATION_RELEASE_SELLER_CODE = /*$$(*/
"SubrogationRelease.sellerCode"; /*)*/
public static final String SUBROGATION_RELEASE_FACTOR = /*$$(*/ "SubrogationRelease.factor"; /*)*/
public static final String SUBROGATION_RELEASE_PARTNER_SEQ = /*$$(*/
"SubrogationRelease.partnerSeq"; /*)*/
public static final String SUBROGATION_RELEASE_INVOICE_ID = /*$$(*/
"SubrogationRelease.invoiceId"; /*)*/
public static final String SUBROGATION_RELEASE_INVOICE_DATE = /*$$(*/
"SubrogationRelease.invoiceDate"; /*)*/
public static final String SUBROGATION_RELEASE_DUE_DATE = /*$$(*/
"SubrogationRelease.dueDate"; /*)*/
public static final String SUBROGATION_RELEASE_IN_TAX_TOTAL = /*$$(*/
"SubrogationRelease.inTaxtTotal"; /*)*/
public static final String SUBROGATION_RELEASE_CURRENCY_CODE = /*$$(*/
"SubrogationRelease.currencyCode"; /*)*/
public static final String SUBROGATION_RELEASE_INVOICE_TOTAL = /*$$(*/
"SubrogationRelease.invoiceTotal"; /*)*/
public static final String SUBROGATION_RELEASE_CREDIT_TOTAL = /*$$(*/
"SubrogationRelease.creditTotal"; /*)*/
public static final String SUBROGATION_RELEASE_GRAND_TOTAL = /*$$(*/
"SubrogationRelease.grandTotal"; /*)*/
public static final String SUBROGATION_RELEASE_COMPANY_NAME = /*$$(*/
"SubrogationRelease.company"; /*)*/
public static final String SUBROGATION_RELEASE_SEQUENCE_NUMBER = /*$$(*/
"SubrogationRelease.sequenceNumber"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_TITLE = /*$$(*/ "ChequeDepositSlip.title"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_PRINTED_ON = /*$$(*/
"ChequeDepositSlip.printedOn"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_NUMBER = /*$$(*/ "ChequeDepositSlip.number"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_DATE = /*$$(*/
"ChequeDepositSlip.depositDate"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_CHEQUE_NUMBERS = /*$$(*/
"ChequeDepositSlip.chequeNumbers"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_BANK = /*$$(*/ "ChequeDepositSlip.bank"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_ACCOUNT_NUMBER = /*$$(*/
"ChequeDepositSlip.accountNumber"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_INDIVIDUAL = /*$$(*/
"ChequeDepositSlip.individual"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_ISSUER = /*$$(*/ "ChequeDepositSlip.issuer"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_PAYER = /*$$(*/ "ChequeDepositSlip.payer"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_CHEQUE_NUMBER = /*$$(*/
"ChequeDepositSlip.chequeNumber"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_PAYMENT_DATE = /*$$(*/
"ChequeDepositSlip.paymentDate"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_CHEQUE_DATE = /*$$(*/
"ChequeDepositSlip.chequeDate"; /*)*/
public static final String CHEQUE_DEPOSIT_SLIP_AMOUNT = /*$$(*/ "ChequeDepositSlip.amount"; /*)*/
public static final String ACCOUNTING_REPORT_16_TITLE =
/*$$(*/ "AccountingReportType16.title"; /*)*/
public static final String ACCOUNTING_REPORT_16_COMPANY =
/*$$(*/ "AccountingReportType16.company"; /*)*/
public static final String ACCOUNTING_REPORT_16_CURRENCY =
/*$$(*/ "AccountingReportType16.currency"; /*)*/
public static final String ACCOUNTING_REPORT_16_END_DATE =
/*$$(*/ "AccountingReportType16.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_16_YEAR =
/*$$(*/ "AccountingReportType16.year"; /*)*/
public static final String ACCOUNTING_REPORT_16_PERIOD =
/*$$(*/ "AccountingReportType16.period"; /*)*/
public static final String ACCOUNTING_REPORT_16_FROM_DATE =
/*$$(*/ "AccountingReportType16.from"; /*)*/
public static final String ACCOUNTING_REPORT_16_TO_DATE =
/*$$(*/ "AccountingReportType16.to"; /*)*/
public static final String ACCOUNTING_REPORT_16_REFERENCE =
/*$$(*/ "AccountingReportType16.reference"; /*)*/
public static final String ACCOUNTING_REPORT_16_ASSET_NAME =
/*$$(*/ "AccountingReportType16.asset_name"; /*)*/
public static final String ACCOUNTING_REPORT_16_ACCOUNT_NAME =
/*$$(*/ "AccountingReportType16.account_name"; /*)*/
public static final String ACCOUNTING_REPORT_16_COMPUTATION_METHOD =
/*$$(*/ "AccountingReportType16.computaion_method"; /*)*/
public static final String ACCOUNTING_REPORT_16_DURATION =
/*$$(*/ "AccountingReportType16.duration"; /*)*/
public static final String ACCOUNTING_REPORT_16_ACQISITION_DATE =
/*$$(*/ "AccountingReportType16.acquisition_date"; /*)*/
public static final String ACCOUNTING_REPORT_16_GROSS_VALUE =
/*$$(*/ "AccountingReportType16.gross_value"; /*)*/
public static final String ACCOUNTING_REPORT_ASSET_COMPUTATION_METHOD_LINEAR =
/*$$(*/ "linear"; /*)*/
public static final String ACCOUNTING_REPORT_ASSET_COMPUTATION_METHOD_DIGRESSIVE =
/*$$(*/ "degressive"; /*)*/
public static final String ACCOUNTING_REPORT_17_TITLE =
/*$$(*/ "AccountingReportType17.title"; /*)*/
public static final String ACCOUNTING_REPORT_17_COMPANY =
/*$$(*/ "AccountingReportType17.company"; /*)*/
public static final String ACCOUNTING_REPORT_17_CURRENCY =
/*$$(*/ "AccountingReportType17.currency"; /*)*/
public static final String ACCOUNTING_REPORT_17_END_DATE =
/*$$(*/ "AccountingReportType17.endDate"; /*)*/
public static final String ACCOUNTING_REPORT_17_YEAR =
/*$$(*/ "AccountingReportType17.year"; /*)*/
public static final String ACCOUNTING_REPORT_17_PERIOD =
/*$$(*/ "AccountingReportType17.period"; /*)*/
public static final String ACCOUNTING_REPORT_17_FROM_DATE =
/*$$(*/ "AccountingReportType17.from"; /*)*/
public static final String ACCOUNTING_REPORT_17_TO_DATE =
/*$$(*/ "AccountingReportType17.to"; /*)*/
public static final String ACCOUNTING_REPORT_17_REFERENCE =
/*$$(*/ "AccountingReportType17.reference"; /*)*/
public static final String ACCOUNTING_REPORT_17_ASSET_NAME =
/*$$(*/ "AccountingReportType17.asset_name"; /*)*/
public static final String ACCOUNTING_REPORT_17_COMPUTATION_METHOD =
/*$$(*/ "AccountingReportType17.computation_method"; /*)*/
public static final String ACCOUNTING_REPORT_17_DURATION =
/*$$(*/ "AccountingReportType17.duration"; /*)*/
public static final String ACCOUNTING_REPORT_17_ACQISITION_DATE =
/*$$(*/ "AccountingReportType17.acquisition_date"; /*)*/
public static final String ACCOUNTING_REPORT_17_RESIDUAL_VALUE =
/*$$(*/ "AccountingReportType17.residual_value"; /*)*/
public static final String ACCOUNTING_REPORT_17_GROSS_VALUES =
/*$$(*/ "AccountingReportType17.gross_values"; /*)*/
public static final String ACCOUNTING_REPORT_17_ORIGINAL_VALUE =
/*$$(*/ "AccountingReportType17.original_value"; /*)*/
public static final String ACCOUNTING_REPORT_17_ACQISITION =
/*$$(*/ "AccountingReportType17.acquisition"; /*)*/
public static final String ACCOUNTING_REPORT_17_ASSET_DISPOSAL =
/*$$(*/ "AccountingReportType17.asset_disposal"; /*)*/
public static final String ACCOUNTING_REPORT_17_YEAR_END_VALUE =
/*$$(*/ "AccountingReportType17.year_end_value"; /*)*/
public static final String ACCOUNTING_REPORT_17_DEPRECIATION =
/*$$(*/ "AccountingReportType17.depreciation"; /*)*/
public static final String ACCOUNTING_REPORT_17_YEAR_START_VALUE =
/*$$(*/ "AccountingReportType17.year_start_value"; /*)*/
public static final String ACCOUNTING_REPORT_17_DEPRECIATION_CHARGE =
/*$$(*/ "AccountingReportType17.depreciation_charge"; /*)*/
public static final String INVOICE_PAYMENT_DATE = /*$$(*/ "InvoicePayment.date"; /*)*/
public static final String INVOICE_PAYMENT_TYPE = /*$$(*/ "InvoicePayment.type"; /*)*/
public static final String INVOICE_PAYMENT_PAYMENT_MODE = /*$$(*/
"InvoicePayment.payment_mode"; /*)*/
public static final String INVOICE_PAYMENT_AMOUNT = /*$$(*/ "InvoicePayment.amount"; /*)*/
}

View File

@ -0,0 +1,134 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.AccountChart;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.repo.AccountChartRepository;
import com.axelor.apps.account.db.repo.AccountConfigRepository;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.ImportConfiguration;
import com.axelor.apps.base.db.repo.CompanyRepository;
import com.axelor.apps.base.service.imports.importer.FactoryImporter;
import com.axelor.exception.AxelorException;
import com.axelor.exception.service.TraceBackService;
import com.axelor.meta.MetaFiles;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.FileUtils;
public class AccountChartService {
@Inject private FactoryImporter factoryImporter;
@Inject private MetaFiles metaFiles;
protected AccountConfigRepository accountConfigRepo;
protected CompanyRepository companyRepo;
protected AccountChartRepository accountChartRepository;
@Inject
public AccountChartService(
AccountConfigRepository accountConfigRepo,
CompanyRepository companyRepo,
AccountChartRepository accountChartRepository) {
this.accountConfigRepo = accountConfigRepo;
this.companyRepo = companyRepo;
this.accountChartRepository = accountChartRepository;
}
public Boolean installAccountChart(AccountChart act, Company company, AccountConfig accountConfig)
throws AxelorException {
try {
if (act.getMetaFile() == null) {
return false;
}
InputStream inputStream = this.getClass().getResourceAsStream("/l10n/chart-config.xml");
if (inputStream == null) {
return false;
}
File configFile = createConfigFile(inputStream);
Map<String, Object> importContext = new HashMap<String, Object>();
importContext.put("_companyId", company.getId());
importAccountChartData(act, configFile, importContext);
updateChartCompany(act, company, accountConfig);
FileUtils.forceDelete(configFile);
return true;
} catch (IOException e) {
TraceBackService.trace(e);
return false;
}
}
private File createConfigFile(InputStream inputStream) throws IOException, FileNotFoundException {
File configFile = File.createTempFile("input-config", ".xml");
FileOutputStream outputStream = new FileOutputStream(configFile);
int read = 0;
byte[] bytes = new byte[1024];
while ((read = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, read);
}
outputStream.close();
return configFile;
}
@Transactional
public void updateChartCompany(AccountChart act, Company company, AccountConfig accountConfig) {
accountConfig = accountConfigRepo.find(accountConfig.getId());
accountConfig.setHasChartImported(true);
accountConfigRepo.save(accountConfig);
act = accountChartRepository.find(act.getId());
company = companyRepo.find(company.getId());
Set<Company> companySet = act.getCompanySet();
companySet.add(company);
act.setCompanySet(companySet);
accountChartRepository.save(act);
}
public void importAccountChartData(
AccountChart act, File configFile, Map<String, Object> importContext)
throws IOException, AxelorException {
ImportConfiguration importConfiguration = new ImportConfiguration();
importConfiguration.setDataMetaFile(act.getMetaFile());
importConfiguration.setBindMetaFile(metaFiles.upload(configFile));
factoryImporter.createImporter(importConfiguration).run(importContext);
}
}

View File

@ -0,0 +1,319 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountClearance;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.Tax;
import com.axelor.apps.account.db.repo.AccountClearanceRepository;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.base.service.tax.TaxService;
import com.axelor.apps.base.service.user.UserService;
import com.axelor.auth.db.User;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountClearanceService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected MoveService moveService;
protected MoveLineService moveLineService;
protected MoveLineRepository moveLineRepo;
protected SequenceService sequenceService;
protected ReconcileService reconcileService;
protected TaxService taxService;
protected TaxAccountService taxAccountService;
protected AccountClearanceRepository accountClearanceRepo;
protected AppBaseService appBaseService;
protected User user;
@Inject
public AccountClearanceService(
UserService userService,
AppBaseService appBaseService,
MoveService moveService,
MoveLineService moveLineService,
MoveLineRepository moveLineRepo,
SequenceService sequenceService,
ReconcileService reconcileService,
TaxService taxService,
TaxAccountService taxAccountService,
AccountClearanceRepository accountClearanceRepo) {
this.appBaseService = appBaseService;
this.user = userService.getUser();
this.moveService = moveService;
this.moveLineService = moveLineService;
this.moveLineRepo = moveLineRepo;
this.sequenceService = sequenceService;
this.reconcileService = reconcileService;
this.taxService = taxService;
this.taxAccountService = taxAccountService;
this.accountClearanceRepo = accountClearanceRepo;
}
public List<? extends MoveLine> getExcessPayment(AccountClearance accountClearance)
throws AxelorException {
Company company = accountClearance.getCompany();
this.testCompanyField(company);
List<? extends MoveLine> moveLineList =
moveLineRepo
.all()
.filter(
"self.company = ?1 AND self.account.useForPartnerBalance = 'true' "
+ "AND (self.move.statusSelect = ?2 OR self.move.statusSelect = ?3) "
+ "AND self.amountRemaining > 0 AND self.amountRemaining <= ?4 AND self.credit > 0 AND self.account in ?5 AND self.date <= ?6",
company,
MoveRepository.STATUS_VALIDATED,
MoveRepository.STATUS_DAYBOOK,
accountClearance.getAmountThreshold(),
company.getAccountConfig().getClearanceAccountSet(),
accountClearance.getDateThreshold())
.fetch();
log.debug("Liste des trop perçus récupérés : {}", moveLineList);
return moveLineList;
}
@SuppressWarnings("unchecked")
@Transactional(rollbackOn = {Exception.class})
public void setExcessPayment(AccountClearance accountClearance) throws AxelorException {
accountClearance.setMoveLineSet(new HashSet<MoveLine>());
List<MoveLine> moveLineList = (List<MoveLine>) this.getExcessPayment(accountClearance);
if (moveLineList != null && moveLineList.size() != 0) {
accountClearance.getMoveLineSet().addAll(moveLineList);
}
accountClearanceRepo.save(accountClearance);
}
@Transactional(rollbackOn = {Exception.class})
public void validateAccountClearance(AccountClearance accountClearance) throws AxelorException {
Company company = accountClearance.getCompany();
AccountConfig accountConfig = company.getAccountConfig();
Tax tax = accountConfig.getStandardRateTax();
BigDecimal taxRate =
taxService.getTaxRate(tax, appBaseService.getTodayDateTime().toLocalDate());
Account taxAccount = taxAccountService.getAccount(tax, company, false, false);
Account profitAccount = accountConfig.getProfitAccount();
Journal journal = accountConfig.getAccountClearanceJournal();
Set<MoveLine> moveLineList = accountClearance.getMoveLineSet();
for (MoveLine moveLine : moveLineList) {
Move move =
this.createAccountClearanceMove(
moveLine, taxRate, taxAccount, profitAccount, company, journal, accountClearance);
moveService.getMoveValidateService().validate(move);
}
accountClearance.setStatusSelect(AccountClearanceRepository.STATUS_VALIDATED);
accountClearance.setDateTime(appBaseService.getTodayDateTime());
accountClearance.setName(
sequenceService.getSequenceNumber(SequenceRepository.ACCOUNT_CLEARANCE, company));
accountClearanceRepo.save(accountClearance);
}
public Move createAccountClearanceMove(
MoveLine moveLine,
BigDecimal taxRate,
Account taxAccount,
Account profitAccount,
Company company,
Journal journal,
AccountClearance accountClearance)
throws AxelorException {
Partner partner = moveLine.getPartner();
// Move
Move move =
moveService
.getMoveCreateService()
.createMove(
journal, company, null, partner, null, MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
// Debit MoveLine 411
BigDecimal amount = moveLine.getAmountRemaining();
MoveLine debitMoveLine =
moveLineService.createMoveLine(
move,
partner,
moveLine.getAccount(),
amount,
true,
appBaseService.getTodayDateTime().toLocalDate(),
1,
null,
null);
move.getMoveLineList().add(debitMoveLine);
// Credit MoveLine 77. (profit account)
BigDecimal divid = taxRate.add(BigDecimal.ONE);
BigDecimal profitAmount =
amount
.divide(divid, AppBaseService.DEFAULT_NB_DECIMAL_DIGITS, RoundingMode.HALF_EVEN)
.setScale(AppBaseService.DEFAULT_NB_DECIMAL_DIGITS, RoundingMode.HALF_EVEN);
MoveLine creditMoveLine1 =
moveLineService.createMoveLine(
move,
partner,
profitAccount,
profitAmount,
false,
appBaseService.getTodayDateTime().toLocalDate(),
2,
null,
null);
move.getMoveLineList().add(creditMoveLine1);
// Credit MoveLine 445 (Tax account)
BigDecimal taxAmount = amount.subtract(profitAmount);
MoveLine creditMoveLine2 =
moveLineService.createMoveLine(
move,
partner,
taxAccount,
taxAmount,
false,
appBaseService.getTodayDateTime().toLocalDate(),
3,
null,
null);
move.getMoveLineList().add(creditMoveLine2);
Reconcile reconcile = reconcileService.createReconcile(debitMoveLine, moveLine, amount, false);
if (reconcile != null) {
reconcileService.confirmReconcile(reconcile, true);
}
debitMoveLine.setAccountClearance(accountClearance);
creditMoveLine1.setAccountClearance(accountClearance);
creditMoveLine2.setAccountClearance(accountClearance);
return move;
}
public AccountClearance createAccountClearance(
Company company,
String name,
BigDecimal amountThreshold,
LocalDate dateThreshold,
List<MoveLine> moveLineSet) {
AccountClearance accountClearance = new AccountClearance();
accountClearance.setAmountThreshold(amountThreshold);
accountClearance.setCompany(company);
accountClearance.setDateThreshold(dateThreshold);
accountClearance.getMoveLineSet().addAll(moveLineSet);
accountClearance.setName(name);
accountClearance.setDateTime(appBaseService.getTodayDateTime());
accountClearance.setUser(this.user);
accountClearance.setStatusSelect(AccountClearanceRepository.STATUS_VALIDATED);
return accountClearance;
}
/**
* Procédure permettant de vérifier les champs d'une société
*
* @param company Une société
* @throws AxelorException
*/
public void testCompanyField(Company company) throws AxelorException {
AccountConfig accountConfig = company.getAccountConfig();
if (accountConfig == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
if (accountConfig.getProfitAccount() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
if (accountConfig.getStandardRateTax() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_3),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
if (accountConfig.getClearanceAccountSet() == null
|| accountConfig.getClearanceAccountSet().size() == 0) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_4),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
if (!sequenceService.hasSequence(SequenceRepository.ACCOUNT_CLEARANCE, company)) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_5),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
if (accountConfig.getAccountClearanceJournal() == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_CLEARANCE_6),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
}
}

View File

@ -0,0 +1,383 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.repo.AccountingSituationRepository;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.ZoneOffset;
import java.util.Date;
import java.util.List;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountCustomerService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected AccountingSituationService accountingSituationService;
protected AccountingSituationRepository accSituationRepo;
protected AppBaseService appBaseService;
@Inject
public AccountCustomerService(
AccountingSituationService accountingSituationService,
AccountingSituationRepository accSituationRepo,
AppBaseService appBaseService) {
this.accountingSituationService = accountingSituationService;
this.accSituationRepo = accSituationRepo;
this.appBaseService = appBaseService;
}
public AccountingSituationService getAccountingSituationService() {
return this.accountingSituationService;
}
/**
* Fonction permettant de calculer le solde total d'un tiers
*
* @param partner Un tiers
* @param company Une société
* @return Le solde total
*/
public BigDecimal getBalance(Partner partner, Company company) {
log.debug("Compute balance (Partner : {}, Company : {})", partner.getName(), company.getName());
Query query =
JPA.em()
.createNativeQuery(
"SELECT SUM(COALESCE(m1.sum_remaining,0) - COALESCE(m2.sum_remaining,0) ) "
+ "FROM public.account_move_line AS ml "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.debit > 0 GROUP BY moveline.id, moveline.amount_remaining) AS m1 ON (m1.moveline_id = ml.id) "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.credit > 0 GROUP BY moveline.id, moveline.amount_remaining) AS m2 ON (m2.moveline_id = ml.id) "
+ "LEFT OUTER JOIN public.account_account AS account ON (ml.account = account.id) "
+ "LEFT OUTER JOIN public.account_move AS move ON (ml.move = move.id) "
+ "WHERE ml.partner = ?1 AND move.company = ?2 AND move.ignore_in_accounting_ok IN ('false', null)"
+ "AND account.use_for_partner_balance = 'true'"
+ "AND (move.status_select = ?3 or move.status_select = ?4) AND ml.amount_remaining > 0 ")
.setParameter(1, partner)
.setParameter(2, company)
.setParameter(3, MoveRepository.STATUS_VALIDATED)
.setParameter(4, MoveRepository.STATUS_DAYBOOK);
BigDecimal balance = (BigDecimal) query.getSingleResult();
if (balance == null) {
balance = BigDecimal.ZERO;
}
log.debug("Balance : {}", balance);
return balance;
}
/**
* Fonction permettant de calculer le solde exigible d'un tiers
*
* <p>Calcul du solde exigible du tiers : Montant Total des factures et des échéances rejetées
* échues (date du jour >= date de léchéance)
*
* @param partner Un tiers
* @param company Une société
* @return Le solde exigible
*/
public BigDecimal getBalanceDue(Partner partner, Company company) {
log.debug(
"Compute balance due (Partner : {}, Company : {})", partner.getName(), company.getName());
Query query =
JPA.em()
.createNativeQuery(
"SELECT SUM( COALESCE(m1.sum_remaining,0) - COALESCE(m2.sum_remaining,0) ) "
+ "FROM public.account_move_line AS ml "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.debit > 0 "
+ "AND ((moveline.due_date IS NULL AND moveline.date_val <= ?1) OR (moveline.due_date IS NOT NULL AND moveline.due_date <= ?1)) "
+ "GROUP BY moveline.id, moveline.amount_remaining) AS m1 on (m1.moveline_id = ml.id) "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.credit > 0 "
+ "GROUP BY moveline.id, moveline.amount_remaining) AS m2 ON (m2.moveline_id = ml.id) "
+ "LEFT OUTER JOIN public.account_account AS account ON (ml.account = account.id) "
+ "LEFT OUTER JOIN public.account_move AS move ON (ml.move = move.id) "
+ "WHERE ml.partner = ?2 AND move.company = ?3 AND move.ignore_in_debt_recovery_ok IN ('false', null) "
+ "AND move.ignore_in_accounting_ok IN ('false', null) AND account.use_for_partner_balance = 'true'"
+ "AND (move.status_select = ?4 OR move.status_select = ?5) AND ml.amount_remaining > 0 ")
.setParameter(
1,
Date.from(
appBaseService
.getTodayDate()
.atStartOfDay()
.atZone(ZoneOffset.UTC)
.toInstant()),
TemporalType.DATE)
.setParameter(2, partner)
.setParameter(3, company)
.setParameter(4, MoveRepository.STATUS_VALIDATED)
.setParameter(5, MoveRepository.STATUS_DAYBOOK);
BigDecimal balance = (BigDecimal) query.getSingleResult();
if (balance == null) {
balance = BigDecimal.ZERO;
}
log.debug("Balance due : {}", balance);
return balance;
}
/**
* **************************************** 2. Calcul du solde exigible (relançable) du tiers
* *****************************************
*/
/**
* solde des factures exigibles non bloquées en relance et dont « la date de facture » + « délai
* dacheminement(X) » <« date du jour » si la date de facture = date d'échéance de facture, sinon
* pas de prise en compte du délai d'acheminement **
*/
/**
* solde des échéances rejetées qui ne sont pas bloqués
* *****************************************************
*/
public BigDecimal getBalanceDueDebtRecovery(Partner partner, Company company) {
log.debug(
"Compute balance due debt recovery (Partner : {}, Company : {})",
partner.getName(),
company.getName());
int mailTransitTime = 0;
AccountConfig accountConfig = company.getAccountConfig();
if (accountConfig != null) {
mailTransitTime = accountConfig.getMailTransitTime();
}
// TODO: Replace native query to standard JPQL query
Query query =
JPA.em()
.createNativeQuery(
"SELECT SUM( COALESCE(m1.sum_remaining,0) - COALESCE(m2.sum_remaining,0) ) "
+ "FROM public.account_move_line as ml "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.debit > 0 AND (( moveline.date_val = moveline.due_date AND (moveline.due_date + ?1 ) < ?2 ) "
+ "OR (moveline.due_date IS NOT NULL AND moveline.date_val != moveline.due_date AND moveline.due_date < ?2)"
+ "OR (moveline.due_date IS NULL AND moveline.date_val < ?2)) "
+ "GROUP BY moveline.id, moveline.amount_remaining) AS m1 ON (m1.moveline_id = ml.id) "
+ "LEFT OUTER JOIN ( "
+ "SELECT moveline.amount_remaining AS sum_remaining, moveline.id AS moveline_id "
+ "FROM public.account_move_line AS moveline "
+ "WHERE moveline.credit > 0 "
+ "GROUP BY moveline.id, moveline.amount_remaining) AS m2 ON (m2.moveline_id = ml.id) "
+ "LEFT OUTER JOIN public.account_account AS account ON (ml.account = account.id) "
+ "LEFT OUTER JOIN public.account_move AS move ON (ml.move = move.id) "
+ "LEFT JOIN public.account_invoice AS invoice ON (move.invoice = invoice.id) "
+ "WHERE ml.partner = ?3 AND move.company = ?4 AND move.ignore_in_debt_recovery_ok in ('false', null) "
+ "AND move.ignore_in_accounting_ok IN ('false', null) AND account.use_for_partner_balance = 'true'"
+ "AND (move.status_select = ?5 OR move.status_select = ?6) AND ml.amount_remaining > 0 AND invoice.debt_recovery_blocking_ok = FALSE ")
.setParameter(1, mailTransitTime)
.setParameter(
2,
Date.from(
appBaseService
.getTodayDate()
.atStartOfDay()
.atZone(ZoneOffset.UTC)
.toInstant()),
TemporalType.DATE)
.setParameter(3, partner)
.setParameter(4, company)
.setParameter(5, MoveRepository.STATUS_VALIDATED)
.setParameter(6, MoveRepository.STATUS_DAYBOOK);
BigDecimal balance = (BigDecimal) query.getSingleResult();
if (balance == null) {
balance = BigDecimal.ZERO;
}
log.debug("Balance due debt recovery : {}", balance);
return balance;
}
/**
* Méthode permettant de récupérer l'ensemble des lignes d'écriture pour une société et un tiers
*
* @param partner Un tiers
* @param company Une société
* @return
*/
public List<? extends MoveLine> getMoveLine(Partner partner, Company company) {
return Beans.get(MoveLineRepository.class)
.all()
.filter("self.partner = ?1 AND self.move.company = ?2", partner, company)
.fetch();
}
/**
* Procédure mettant à jour les soldes du compte client des tiers pour une société
*
* @param partnerList Une liste de tiers à mettre à jour
* @param company Une société
*/
public void updatePartnerAccountingSituation(
List<Partner> partnerList,
Company company,
boolean updateCustAccount,
boolean updateDueCustAccount,
boolean updateDueDebtRecoveryCustAccount)
throws AxelorException {
for (Partner partner : partnerList) {
AccountingSituation accountingSituation =
accountingSituationService.getAccountingSituation(partner, company);
if (accountingSituation == null) {
accountingSituation =
accountingSituationService.createAccountingSituation(partner, company);
}
if (accountingSituation != null) {
this.updateAccountingSituationCustomerAccount(
accountingSituation,
updateCustAccount,
updateDueCustAccount,
updateDueDebtRecoveryCustAccount);
}
}
}
@Transactional(rollbackOn = {Exception.class})
public void flagPartners(List<Partner> partnerList, Company company) throws AxelorException {
for (Partner partner : partnerList) {
AccountingSituation accountingSituation =
accountingSituationService.getAccountingSituation(partner, company);
if (accountingSituation == null) {
accountingSituation =
accountingSituationService.createAccountingSituation(partner, company);
}
if (accountingSituation != null) {
accountingSituation.setCustAccountMustBeUpdateOk(true);
accSituationRepo.save(accountingSituation);
}
}
}
@Transactional(rollbackOn = {Exception.class})
public AccountingSituation updateAccountingSituationCustomerAccount(
AccountingSituation accountingSituation,
boolean updateCustAccount,
boolean updateDueCustAccount,
boolean updateDueDebtRecoveryCustAccount)
throws AxelorException {
Partner partner = accountingSituation.getPartner();
Company company = accountingSituation.getCompany();
log.debug(
"Update customer account (Partner : {}, Company : {}, Update balance : {}, balance due : {}, balance due debt recovery : {})",
partner.getName(),
company.getName(),
updateCustAccount,
updateDueCustAccount,
updateDueDebtRecoveryCustAccount);
if (updateCustAccount) {
accountingSituation.setBalanceCustAccount(this.getBalance(partner, company));
}
if (updateDueCustAccount) {
accountingSituation.setBalanceDueCustAccount(this.getBalanceDue(partner, company));
}
if (updateDueDebtRecoveryCustAccount) {
accountingSituation.setBalanceDueDebtRecoveryCustAccount(
this.getBalanceDueDebtRecovery(partner, company));
}
accountingSituation.setCustAccountMustBeUpdateOk(false);
accSituationRepo.save(accountingSituation);
return accountingSituation;
}
public Account getPartnerAccount(Partner partner, Company company, boolean isSupplierInvoice)
throws AxelorException {
return isSupplierInvoice
? getSupplierAccount(partner, company)
: getCustomerAccount(partner, company);
}
protected Account getCustomerAccount(Partner partner, Company company) throws AxelorException {
Account customerAccount = accountingSituationService.getCustomerAccount(partner, company);
if (customerAccount == null) {
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNT_CUSTOMER_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
return customerAccount;
}
protected Account getSupplierAccount(Partner partner, Company company) throws AxelorException {
Account supplierAccount = accountingSituationService.getSupplierAccount(partner, company);
if (supplierAccount == null) {
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNT_CUSTOMER_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
return supplierAccount;
}
}

View File

@ -0,0 +1,71 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
import com.axelor.apps.account.db.FiscalPosition;
import com.axelor.apps.account.db.FixedAssetCategory;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.service.tax.AccountManagementService;
import com.axelor.exception.AxelorException;
public interface AccountManagementAccountService extends AccountManagementService {
/**
* Get the product tax according to the fiscal position
*
* @param product
* @param company
* @param fiscalPosition
* @param isPurchase Specify if we want get the tax for purchase or sale
* @param fixedAsset Specify if we should get the purchase account for fixed asset or not. Used
* only if isPurchase param is true.
* @return the tax defined for the product, according to the fiscal position
* @throws AxelorException
*/
public Account getProductAccount(
Product product,
Company company,
FiscalPosition fiscalPosition,
boolean isPurchase,
boolean fixedAsset)
throws AxelorException;
/**
* Get the product analytic distribution template
*
* @param product
* @param company
* @return
* @throws AxelorException
*/
public AnalyticDistributionTemplate getAnalyticDistributionTemplate(
Product product, Company company);
/**
* Get the product fixed asset category
*
* @param product
* @param company
* @return
* @throws AxelorException
*/
public FixedAssetCategory getProductFixedAssetCategory(Product product, Company company);
}

View File

@ -0,0 +1,225 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountManagement;
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
import com.axelor.apps.account.db.FiscalPosition;
import com.axelor.apps.account.db.FixedAssetCategory;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Product;
import com.axelor.apps.base.service.tax.AccountManagementServiceImpl;
import com.axelor.apps.base.service.tax.FiscalPositionService;
import com.axelor.apps.base.service.tax.TaxService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.meta.CallMethod;
import com.google.inject.Inject;
import java.lang.invoke.MethodHandles;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountManagementServiceAccountImpl extends AccountManagementServiceImpl
implements AccountManagementAccountService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Inject
public AccountManagementServiceAccountImpl(
FiscalPositionService fiscalPositionService, TaxService taxService) {
super(fiscalPositionService, taxService);
}
/**
* Get the product tax according to the fiscal position
*
* @param product
* @param company
* @param fiscalPosition
* @param isPurchase Specify if we want get the tax for purchase or sale
* @param fixedAsset Specify if we should get the purchase account for fixed asset or not. Used
* only if isPurchase param is true.
* @return the tax defined for the product, according to the fiscal position
* @throws AxelorException
*/
public Account getProductAccount(
Product product,
Company company,
FiscalPosition fiscalPosition,
boolean isPurchase,
boolean fixedAsset)
throws AxelorException {
log.debug(
"Get the account for the product {} (company : {}, purchase : {}, fixed asset : {}, fiscal position : {})",
new Object[] {
product.getCode(),
company.getName(),
isPurchase,
fixedAsset,
fiscalPosition != null ? fiscalPosition.getCode() : null
});
Account generalAccount =
this.getProductAccount(product, company, isPurchase, fixedAsset, CONFIG_OBJECT_PRODUCT);
Account account =
new FiscalPositionAccountServiceImpl().getAccount(fiscalPosition, generalAccount);
if (account != null) {
return account;
}
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNT_MANAGEMENT_1_ACCOUNT),
product.getCode(),
company.getName());
}
/**
* Get the product tax
*
* @param product
* @param company
* @param isPurchase
* @param fixedAsset Specify if we should get the purchase account for fixed asset or not. Used
* only if isPurchase param is true.
* @param configObject Specify if we want get the tax from the product or its product family
* <li>1 : product
* <li>2 : product family
* @return
* @throws AxelorException
*/
@CallMethod
protected Account getProductAccount(
Product product, Company company, boolean isPurchase, boolean fixedAsset, int configObject) {
AccountManagement accountManagement = this.getAccountManagement(product, company, configObject);
Account account = null;
if (accountManagement != null) {
if (isPurchase) {
if (fixedAsset) {
account = accountManagement.getPurchFixedAssetsAccount();
} else {
account = accountManagement.getPurchaseAccount();
}
} else {
account = accountManagement.getSaleAccount();
}
}
if (account == null && configObject == CONFIG_OBJECT_PRODUCT) {
return getProductAccount(
product, company, isPurchase, fixedAsset, CONFIG_OBJECT_PRODUCT_FAMILY);
}
return account;
}
/**
* Get the product analytic distribution template
*
* @param product
* @param company
* @return
* @throws AxelorException
*/
public AnalyticDistributionTemplate getAnalyticDistributionTemplate(
Product product, Company company) {
return getAnalyticDistributionTemplate(product, company, CONFIG_OBJECT_PRODUCT);
}
/**
* Get the product analytic distribution template
*
* @param product
* @param compan
* @param configObject Specify if we want get the tax from the product or its product family
* <li>1 : product
* <li>2 : product family
* @return
* @throws AxelorException
*/
protected AnalyticDistributionTemplate getAnalyticDistributionTemplate(
Product product, Company company, int configObject) {
AccountManagement accountManagement = this.getAccountManagement(product, company, configObject);
AnalyticDistributionTemplate analyticDistributionTemplate = null;
if (accountManagement != null) {
analyticDistributionTemplate = accountManagement.getAnalyticDistributionTemplate();
}
if (analyticDistributionTemplate == null && configObject == CONFIG_OBJECT_PRODUCT) {
return getAnalyticDistributionTemplate(product, company, CONFIG_OBJECT_PRODUCT_FAMILY);
}
return analyticDistributionTemplate;
}
/**
* Get the product fixed asset category
*
* @param product
* @param company
* @return
* @throws AxelorException
*/
public FixedAssetCategory getProductFixedAssetCategory(Product product, Company company) {
return getProductFixedAssetCategory(product, company, CONFIG_OBJECT_PRODUCT);
}
/**
* Get the product fixed asset category
*
* @param product
* @param company
* @param configObject Specify if we want get the fixed asset category from the product or its
* product family
* <li>1 : product
* <li>2 : product family
* @return
* @throws AxelorException
*/
protected FixedAssetCategory getProductFixedAssetCategory(
Product product, Company company, int configObject) {
AccountManagement accountManagement = this.getAccountManagement(product, company, configObject);
FixedAssetCategory fixedAssetCategory = null;
if (accountManagement != null) {
fixedAssetCategory = accountManagement.getFixedAssetCategory();
}
if (fixedAssetCategory == null && configObject == CONFIG_OBJECT_PRODUCT) {
return getProductFixedAssetCategory(product, company, CONFIG_OBJECT_PRODUCT_FAMILY);
}
return fixedAssetCategory;
}
}

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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.db.JPA;
import com.google.inject.Inject;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/** Debit balance = debit - credit */
public static final Integer BALANCE_TYPE_DEBIT_BALANCE = 1;
/** Credit balance = credit - debit */
public static final Integer BALANCE_TYPE_CREDIT_BALANCE = 2;
public static final int MAX_LEVEL_OF_ACCOUNT = 20;
protected AccountRepository accountRepository;
@Inject
public AccountService(AccountRepository accountRepository) {
this.accountRepository = accountRepository;
}
/**
* Compute the balance of the account, depending of the balance type
*
* @param account Account
* @param balanceType
* <p>1 : debit balance = debit - credit
* <p>2 : credit balance = credit - debit
* @return The balance (debit balance or credit balance)
*/
public BigDecimal computeBalance(Account account, int balanceType) {
Query balanceQuery =
JPA.em()
.createQuery(
"select sum(self.debit - self.credit) from MoveLine self where self.account = :account "
+ "and self.move.ignoreInAccountingOk IN ('false', null) and self.move.statusSelect IN (2, 3)");
balanceQuery.setParameter("account", account);
BigDecimal balance = (BigDecimal) balanceQuery.getSingleResult();
if (balance != null) {
if (balanceType == BALANCE_TYPE_CREDIT_BALANCE) {
balance = balance.negate();
}
log.debug("Account balance : {}", balance);
return balance;
} else {
return BigDecimal.ZERO;
}
}
public List<Long> getAllAccountsSubAccountIncluded(List<Long> accountList) {
return getAllAccountsSubAccountIncluded(accountList, 0);
}
public List<Long> getAllAccountsSubAccountIncluded(List<Long> accountList, int counter) {
if (counter > MAX_LEVEL_OF_ACCOUNT) {
return new ArrayList<>();
}
counter++;
List<Long> allAccountsSubAccountIncluded = new ArrayList<>();
if (accountList != null && !accountList.isEmpty()) {
allAccountsSubAccountIncluded.addAll(accountList);
for (Long accountId : accountList) {
allAccountsSubAccountIncluded.addAll(
getAllAccountsSubAccountIncluded(getSubAccounts(accountId), counter));
}
}
return allAccountsSubAccountIncluded;
}
public List<Long> getSubAccounts(Long accountId) {
return accountRepository
.all()
.filter("self.parentAccount.id = ?1", accountId)
.select("id")
.fetch(0, 0)
.stream()
.map(m -> (Long) m.get("id"))
.collect(Collectors.toList());
}
}

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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Year;
import com.axelor.exception.AxelorException;
import com.google.inject.persist.Transactional;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.tuple.Pair;
public interface AccountingCloseAnnualService {
@Transactional(rollbackOn = {AxelorException.class, RuntimeException.class})
public List<Move> generateCloseAnnualAccount(
Year year,
Account account,
Partner partner,
LocalDate endOfYearDate,
LocalDate reportedBalanceDate,
String origin,
String moveDescription,
boolean closeYear,
boolean openYear,
boolean allocatePerPartner)
throws AxelorException;
public List<Long> getAllAccountOfYear(Set<Account> accountSet, Year year);
public List<Pair<Long, Long>> assignPartner(
List<Long> accountIdList, Year year, boolean allocatePerPartner);
}

View File

@ -0,0 +1,373 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.move.MoveCreateService;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveValidateService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Year;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.persistence.Query;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountingCloseAnnualServiceImpl implements AccountingCloseAnnualService {
private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected MoveCreateService moveCreateService;
protected MoveLineService moveLineService;
protected AccountConfigService accountConfigService;
protected MoveRepository moveRepository;
protected MoveValidateService moveValidateService;
protected ReconcileService reconcileService;
protected AccountService accountService;
protected AccountRepository accountRepository;
protected int counter = 0;
@Inject
public AccountingCloseAnnualServiceImpl(
MoveCreateService moveCreateService,
MoveLineService moveLineService,
AccountConfigService accountConfigService,
MoveRepository moveRepository,
MoveValidateService moveValidateService,
ReconcileService reconcileService,
AccountService accountService,
AccountRepository accountRepository) {
this.moveCreateService = moveCreateService;
this.moveLineService = moveLineService;
this.accountConfigService = accountConfigService;
this.moveRepository = moveRepository;
this.moveValidateService = moveValidateService;
this.reconcileService = reconcileService;
this.accountService = accountService;
this.accountRepository = accountRepository;
}
@Transactional(rollbackOn = {AxelorException.class, RuntimeException.class})
public List<Move> generateCloseAnnualAccount(
Year year,
Account account,
Partner partner,
LocalDate endOfYearDate,
LocalDate reportedBalanceDate,
String origin,
String moveDescription,
boolean closeYear,
boolean openYear,
boolean allocatePerPartner)
throws AxelorException {
List<Move> moveList = new ArrayList<>();
Move closeYearMove = null;
Move openYearMove = null;
if (closeYear) {
closeYearMove =
generateCloseAnnualAccountMove(
year,
account,
endOfYearDate,
endOfYearDate,
origin,
moveDescription,
partner,
false,
allocatePerPartner);
if (closeYearMove == null) {
return null;
}
moveList.add(closeYearMove);
}
if (openYear) {
openYearMove =
generateCloseAnnualAccountMove(
year,
account,
reportedBalanceDate,
endOfYearDate,
origin,
moveDescription,
partner,
true,
allocatePerPartner);
if (openYearMove == null) {
return null;
}
moveList.add(openYearMove);
}
if (closeYearMove != null && openYearMove != null) {
reconcile(closeYearMove, openYearMove);
}
return moveList;
}
protected Move generateCloseAnnualAccountMove(
Year year,
Account account,
LocalDate moveDate,
LocalDate originDate,
String origin,
String moveDescription,
Partner partner,
boolean isReverse,
boolean allocatePerPartner)
throws AxelorException {
Company company = account.getCompany();
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
BigDecimal balance = computeBalance(year, account, partner, allocatePerPartner);
if (balance.compareTo(BigDecimal.ZERO) == 0) {
return null;
}
Integer functionalOriginSelect = null;
if (isReverse) {
balance = balance.negate();
functionalOriginSelect = MoveRepository.FUNCTIONAL_ORIGIN_OPENING;
} else {
functionalOriginSelect = MoveRepository.FUNCTIONAL_ORIGIN_CLOSURE;
}
Move move =
moveCreateService.createMove(
accountConfigService.getReportedBalanceJournal(accountConfig),
company,
company.getCurrency(),
partner,
moveDate,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC,
false,
false,
!isReverse);
move.setFunctionalOriginSelect(functionalOriginSelect);
counter = 0;
this.generateCloseAnnualMoveLine(
move, origin, account, moveDescription, originDate, balance.negate());
this.generateCloseAnnualMoveLine(
move,
origin,
getYearClosureOrOpeningAccount(accountConfig, isReverse),
moveDescription,
originDate,
balance);
if (move.getMoveLineList() != null && !move.getMoveLineList().isEmpty()) {
moveValidateService.validate(move);
} else {
moveRepository.remove(move);
return null;
}
return move;
}
protected Account getYearClosureOrOpeningAccount(AccountConfig accountConfig, boolean isReverse)
throws AxelorException {
if (isReverse) {
return accountConfigService.getYearOpeningAccount(accountConfig);
} else {
return accountConfigService.getYearClosureAccount(accountConfig);
}
}
protected MoveLine generateCloseAnnualMoveLine(
Move move,
String origin,
Account account,
String moveDescription,
LocalDate originDate,
BigDecimal balance)
throws AxelorException {
LocalDate moveDate = move.getDate();
MoveLine moveLine =
moveLineService.createMoveLine(
move,
move.getPartner(),
account,
balance.abs(),
balance.abs(),
null,
balance.compareTo(BigDecimal.ZERO) == 1,
moveDate,
moveDate,
originDate,
++counter,
origin,
moveDescription);
move.addMoveLineListItem(moveLine);
return moveLine;
}
protected BigDecimal computeBalance(
Year year, Account account, Partner partner, boolean allocatePerPartner) {
String prepareQuery =
"select SUM(self.debit - self.credit) FROM MoveLine as self "
+ "WHERE self.move.ignoreInAccountingOk = false AND self.move.period.year = ?1 AND self.account = ?2 "
+ "AND self.move.statusSelect = ?3 AND self.move.autoYearClosureMove is not true";
if (allocatePerPartner && account.getUseForPartnerBalance()) {
if (partner != null) {
prepareQuery += " AND self.partner = ?4";
} else {
prepareQuery += " AND self.partner is null";
}
}
Query q = JPA.em().createQuery(prepareQuery, BigDecimal.class);
q.setParameter(1, year);
q.setParameter(2, account);
q.setParameter(3, MoveRepository.STATUS_VALIDATED);
if (partner != null) {
q.setParameter(4, partner);
}
BigDecimal result = (BigDecimal) q.getSingleResult();
LOG.debug(
"Balance : {} for the account : {} and the year : {}",
result,
account.getCode(),
year.getCode());
if (result != null) {
return result;
} else {
return BigDecimal.ZERO;
}
}
protected void reconcile(Move move, Move reverseMove) throws AxelorException {
List<MoveLine> moveLineSortedList = move.getMoveLineList();
Collections.sort(moveLineSortedList, Comparator.comparing(MoveLine::getCounter));
List<MoveLine> reverseMoveLineSortedList = reverseMove.getMoveLineList();
Collections.sort(reverseMoveLineSortedList, Comparator.comparing(MoveLine::getCounter));
Iterator<MoveLine> reverseMoveLinesIt = reverseMoveLineSortedList.iterator();
for (MoveLine moveLine : moveLineSortedList) {
MoveLine reverseMoveLine = reverseMoveLinesIt.next();
reconcileService.reconcile(moveLine, reverseMoveLine, false, false);
}
}
public List<Long> getAllAccountOfYear(Set<Account> accountSet, Year year) {
List<Long> accountIdList =
accountService.getAllAccountsSubAccountIncluded(
accountSet.stream().map(Account::getId).collect(Collectors.toList()));
Query q =
JPA.em()
.createQuery(
"select distinct(self.account.id) FROM MoveLine as self "
+ "WHERE self.move.ignoreInAccountingOk = false AND self.move.period.year = ?1 AND self.account.id in (?2) "
+ "AND self.move.statusSelect = ?3 AND self.move.autoYearClosureMove is not true",
Long.class);
q.setParameter(1, year);
q.setParameter(2, accountIdList);
q.setParameter(3, MoveRepository.STATUS_VALIDATED);
List<Long> result = q.getResultList();
return result;
}
public List<Pair<Long, Long>> assignPartner(
List<Long> accountIdList, Year year, boolean allocatePerPartner) {
List<Pair<Long, Long>> accountAndPartnerPair = new ArrayList<>();
for (Long accountId : accountIdList) {
if (allocatePerPartner && accountRepository.find(accountId).getUseForPartnerBalance()) {
for (Long partnerId : getPartner(accountId, year)) {
accountAndPartnerPair.add(Pair.of(accountId, partnerId));
}
} else {
accountAndPartnerPair.add(Pair.of(accountId, null));
}
}
return accountAndPartnerPair;
}
protected List<Long> getPartner(Long accountId, Year year) {
Query q =
JPA.em()
.createQuery(
"select distinct(self.partner.id) FROM MoveLine as self "
+ "WHERE self.move.ignoreInAccountingOk = false AND self.move.period.year = ?1 AND self.account.id = ?2 "
+ "AND self.move.statusSelect = ?3 AND self.move.autoYearClosureMove is not true",
Long.class);
q.setParameter(1, year);
q.setParameter(2, accountId);
q.setParameter(3, MoveRepository.STATUS_VALIDATED);
List<Long> result = q.getResultList();
return result;
}
}

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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountingReport;
import com.axelor.apps.account.db.JournalType;
import com.axelor.exception.AxelorException;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
public interface AccountingReportService {
public String getMoveLineList(AccountingReport accountingReport) throws AxelorException;
public String buildQuery(AccountingReport accountingReport) throws AxelorException;
public String addParams(String paramQuery, Object param);
public String addParams(String paramQuery);
@Transactional
public void setSequence(AccountingReport accountingReport, String sequence);
public String getSequence(AccountingReport accountingReport) throws AxelorException;
public JournalType getJournalType(AccountingReport accountingReport) throws AxelorException;
public Account getAccount(AccountingReport accountingReport);
@Transactional
public void setStatus(AccountingReport accountingReport);
/** @param accountingReport */
@Transactional
public void setPublicationDateTime(AccountingReport accountingReport);
/**
* @param queryFilter
* @return
*/
public BigDecimal getDebitBalance();
/**
* @param queryFilter
* @return
*/
public BigDecimal getCreditBalance();
public BigDecimal getDebitBalanceType4();
public BigDecimal getCreditBalance(AccountingReport accountingReport, String queryFilter);
public BigDecimal getCreditBalanceType4();
public String getReportFileLink(AccountingReport accountingReport, String name)
throws AxelorException;
public boolean isThereTooManyLines(AccountingReport accountingReport) throws AxelorException;
public void testReportedDateField(LocalDate reportedDate) throws AxelorException;
}

View File

@ -0,0 +1,681 @@
/*
* 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.account.service;
import com.axelor.apps.ReportFactory;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.AccountingReport;
import com.axelor.apps.account.db.JournalType;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.apps.account.db.repo.AccountingReportRepository;
import com.axelor.apps.account.db.repo.AnalyticMoveLineRepository;
import com.axelor.apps.account.db.repo.FixedAssetRepository;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.PaymentModeRepository;
import com.axelor.apps.account.db.repo.TaxPaymentMoveLineRepository;
import com.axelor.apps.account.db.repo.TaxRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.report.IReport;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.db.JPA;
import com.axelor.db.Model;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AccountingReportServiceImpl implements AccountingReportService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected AccountingReportRepository accountingReportRepo;
protected AppBaseService appBaseService;
protected String query = "";
protected AccountRepository accountRepo;
protected List<Object> params = new ArrayList<Object>();
protected int paramNumber = 1;
@Inject
public AccountingReportServiceImpl(
AppAccountService appBaseService,
AccountingReportRepository accountingReportRepo,
AccountRepository accountRepo) {
this.accountingReportRepo = accountingReportRepo;
this.accountRepo = accountRepo;
this.appBaseService = appBaseService;
}
@SuppressWarnings("unchecked")
public String getMoveLineList(AccountingReport accountingReport) throws AxelorException {
this.buildQuery(accountingReport);
return this.buildDomainFromQuery();
}
protected String buildDomainFromQuery() {
int i = 1;
String domainQuery = this.query;
for (Object param : params.toArray()) {
String paramStr = "";
if (param instanceof Model) {
paramStr = ((Model) param).getId().toString();
} else if (param instanceof Set) {
Set<Object> paramSet = (Set<Object>) param;
for (Object object : paramSet) {
if (!paramStr.isEmpty()) {
paramStr += ",";
}
paramStr += ((Model) object).getId().toString();
}
} else if (param instanceof LocalDate) {
paramStr = "'" + param.toString() + "'";
} else {
paramStr = param.toString();
}
domainQuery = domainQuery.replace("?" + i, paramStr);
i++;
}
log.debug("domainQuery : {}", domainQuery);
return domainQuery;
}
public String buildQuery(AccountingReport accountingReport) throws AxelorException {
this.initQuery();
if (accountingReport.getCompany() != null) {
this.addParams("self.move.company = ?%d", accountingReport.getCompany());
}
if (accountingReport.getCurrency() != null) {
this.addParams("self.move.companyCurrency = ?%d", accountingReport.getCurrency());
}
if (accountingReport.getDateFrom() != null) {
this.addParams("self.date >= ?%d", accountingReport.getDateFrom());
}
if (accountingReport.getDateTo() != null) {
this.addParams("self.date <= ?%d", accountingReport.getDateTo());
}
if (accountingReport.getDate() != null) {
this.addParams("self.date <= ?%d", accountingReport.getDate());
}
if (accountingReport.getJournal() != null) {
this.addParams("self.move.journal = ?%d", accountingReport.getJournal());
}
if (accountingReport.getPeriod() != null) {
this.addParams("self.move.period = ?%d", accountingReport.getPeriod());
}
if (accountingReport.getAccountSet() != null && !accountingReport.getAccountSet().isEmpty()) {
this.addParams(
"(self.account in (?%d) or self.account.parentAccount in (?%d) "
+ "or self.account.parentAccount.parentAccount in (?%d) or self.account.parentAccount.parentAccount.parentAccount in (?%d) "
+ "or self.account.parentAccount.parentAccount.parentAccount.parentAccount in (?%d) or self.account.parentAccount.parentAccount.parentAccount.parentAccount.parentAccount in (?%d) "
+ "or self.account.parentAccount.parentAccount.parentAccount.parentAccount.parentAccount.parentAccount in (?%d))",
accountingReport.getAccountSet());
}
if (accountingReport.getPartnerSet() != null && !accountingReport.getPartnerSet().isEmpty()) {
this.addParams("self.partner in (?%d)", accountingReport.getPartnerSet());
}
if (accountingReport.getYear() != null) {
this.addParams("self.move.period.year = ?%d", accountingReport.getYear());
}
if (accountingReport.getPaymentMode() != null) {
this.addParams("self.move.paymentMode = ?%d", accountingReport.getPaymentMode());
}
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_CHEQUE_DEPOSIT) {
this.addParams("self.amountPaid > 0 AND self.credit > 0");
}
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_AGED_BALANCE) {
this.addParams("self.account is null or self.account.reconcileOk = 'true'");
this.addParams("self.amountRemaining > 0 AND self.debit > 0");
}
if (accountingReport.getTypeSelect()
== AccountingReportRepository.REPORT_PARNER_GENERAL_LEDGER) {
this.addParams("self.account.useForPartnerBalance = 'true'");
}
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_BALANCE) {
this.addParams("self.account is null or self.account.reconcileOk = 'true'");
}
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_CASH_PAYMENTS) {
this.addParams("self.move.paymentMode.typeSelect = ?%d", PaymentModeRepository.TYPE_CASH);
this.addParams("self.credit > 0");
this.addParams("self.account is null or self.account.reconcileOk = 'true'");
}
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_PAYMENT_DIFFERENCES) {
this.addParams(
"self.account = ?%d",
Beans.get((AccountConfigService.class))
.getAccountConfig(accountingReport.getCompany())
.getCashPositionVariationAccount());
}
if (accountingReport.getTypeSelect()
== AccountingReportRepository.REPORT_VAT_STATEMENT_INVOICE) {
this.addParams("self.taxLine is not null");
this.addParams("self.taxLine.tax.typeSelect = ?%d", TaxRepository.TAX_TYPE_DEBIT);
}
this.addParams("self.move.ignoreInAccountingOk = 'false'");
this.addParams(
"(self.move.statusSelect = "
+ MoveRepository.STATUS_DAYBOOK
+ " OR self.move.statusSelect = "
+ MoveRepository.STATUS_VALIDATED
+ ")");
// FOR EXPORT ONLY :
if (accountingReport.getTypeSelect()
> AccountingReportRepository.EXPORT_PAYROLL_JOURNAL_ENTRY) {
this.addParams(
"(self.move.accountingOk = false OR (self.move.accountingOk = true and self.move.accountingReport = ?%d))",
accountingReport);
}
if (accountingReport.getTypeSelect()
>= AccountingReportRepository.EXPORT_PAYROLL_JOURNAL_ENTRY) {
this.addParams("self.move.journal.notExportOk = false ");
}
if (accountingReport.getTypeSelect()
> AccountingReportRepository.EXPORT_PAYROLL_JOURNAL_ENTRY) {
JournalType journalType = this.getJournalType(accountingReport);
if (journalType != null) {
this.addParams("self.move.journal.journalType = ?%d", journalType);
}
}
if (accountingReport.getTypeSelect() >= AccountingReportRepository.REPORT_PARNER_GENERAL_LEDGER
&& accountingReport.getDisplayOnlyNotCompletelyLetteredMoveLines()) {
this.addParams("self.amountRemaining > 0");
}
log.debug("Query : {}", this.query);
return this.query;
}
protected void initQuery() {
query = "";
paramNumber = 1;
params = new ArrayList<Object>();
this.query = "";
this.params.clear();
this.paramNumber = 1;
}
public String addParams(String paramQuery, Object param) {
log.debug("requete et param : {} : {}", paramQuery, paramNumber);
this.addParams(paramQuery.replaceAll("%d", String.valueOf(paramNumber++)));
this.params.add(param);
return this.query;
}
public String addParams(String paramQuery) {
if (!this.query.equals("")) {
this.query += " AND ";
}
this.query += paramQuery;
return this.query;
}
public void setSequence(AccountingReport accountingReport, String sequence) {
accountingReport.setRef(sequence);
}
public String getSequence(AccountingReport accountingReport) throws AxelorException {
SequenceService sequenceService = Beans.get(SequenceService.class);
int accountingReportTypeSelect = accountingReport.getTypeSelect();
if (accountingReportTypeSelect >= 0 && accountingReportTypeSelect < 1000) {
String seq =
sequenceService.getSequenceNumber(
SequenceRepository.ACCOUNTING_REPORT, accountingReport.getCompany());
if (seq == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNTING_REPORT_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
accountingReport.getCompany().getName());
}
return seq;
} else if (accountingReportTypeSelect >= 1000 && accountingReportTypeSelect < 2000) {
String seq =
sequenceService.getSequenceNumber(
SequenceRepository.MOVE_LINE_EXPORT, accountingReport.getCompany());
if (seq == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNTING_REPORT_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
accountingReport.getCompany().getName());
}
return seq;
} else if (accountingReportTypeSelect >= 2000 && accountingReportTypeSelect < 3000) {
String seq =
sequenceService.getSequenceNumber(
SequenceRepository.ANALYTIC_REPORT, accountingReport.getCompany());
if (seq == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNTING_REPORT_ANALYTIC_REPORT),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
accountingReport.getCompany().getName());
}
return seq;
}
throw new AxelorException(
accountingReport,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.ACCOUNTING_REPORT_UNKNOWN_ACCOUNTING_REPORT_TYPE),
accountingReport.getTypeSelect());
}
public JournalType getJournalType(AccountingReport accountingReport) throws AxelorException {
Company company = accountingReport.getCompany();
AccountConfigService accountConfigService = Beans.get(AccountConfigService.class);
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
switch (accountingReport.getTypeSelect()) {
case AccountingReportRepository.EXPORT_SALES:
return accountConfigService.getSaleJournalType(accountConfig);
case AccountingReportRepository.EXPORT_REFUNDS:
return accountConfigService.getCreditNoteJournalType(accountConfig);
case AccountingReportRepository.EXPORT_TREASURY:
return accountConfigService.getCashJournalType(accountConfig);
case AccountingReportRepository.EXPORT_PURCHASES:
return accountConfigService.getPurchaseJournalType(accountConfig);
default:
break;
}
return null;
}
public Account getAccount(AccountingReport accountingReport) {
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_PAYMENT_DIFFERENCES
&& accountingReport.getCompany() != null) {
return accountRepo
.all()
.filter("self.company = ?1 AND self.code LIKE '58%'", accountingReport.getCompany())
.fetchOne();
}
return null;
}
@Transactional
public void setStatus(AccountingReport accountingReport) {
accountingReport.setStatusSelect(AccountingReportRepository.STATUS_VALIDATED);
accountingReportRepo.save(accountingReport);
}
/** @param accountingReport */
@Transactional
public void setPublicationDateTime(AccountingReport accountingReport) {
accountingReport.setPublicationDateTime(appBaseService.getTodayDateTime());
accountingReportRepo.save(accountingReport);
}
/**
* @param queryFilter
* @return
*/
public BigDecimal getDebitBalance() {
Query q =
JPA.em()
.createQuery(
"select SUM(self.debit) FROM MoveLine as self WHERE " + query, BigDecimal.class);
int i = 1;
for (Object param : params.toArray()) {
q.setParameter(i++, param);
}
BigDecimal result = (BigDecimal) q.getSingleResult();
log.debug("Total debit : {}", result);
if (result != null) {
return result;
} else {
return BigDecimal.ZERO;
}
}
/**
* @param queryFilter
* @return
*/
public BigDecimal getCreditBalance() {
Query q =
JPA.em()
.createQuery(
"select SUM(self.credit) FROM MoveLine as self WHERE " + query, BigDecimal.class);
int i = 1;
for (Object param : params.toArray()) {
q.setParameter(i++, param);
}
BigDecimal result = (BigDecimal) q.getSingleResult();
log.debug("Total debit : {}", result);
if (result != null) {
return result;
} else {
return BigDecimal.ZERO;
}
}
public BigDecimal getDebitBalanceType4() {
Query q =
JPA.em()
.createQuery(
"select SUM(self.amountRemaining) FROM MoveLine as self WHERE " + query,
BigDecimal.class);
int i = 1;
for (Object param : params.toArray()) {
q.setParameter(i++, param);
}
BigDecimal result = (BigDecimal) q.getSingleResult();
log.debug("Total debit : {}", result);
if (result != null) {
return result;
} else {
return BigDecimal.ZERO;
}
}
public BigDecimal getCreditBalance(AccountingReport accountingReport, String queryFilter) {
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_AGED_BALANCE) {
return this.getCreditBalanceType4();
} else {
return this.getCreditBalance();
}
}
public BigDecimal getCreditBalanceType4() {
return this.getDebitBalance().subtract(this.getDebitBalanceType4());
}
public void testReportedDateField(LocalDate reportedDate) throws AxelorException {
if (reportedDate == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CLOSE_NO_REPORTED_BALANCE_DATE));
}
}
@Override
public String getReportFileLink(AccountingReport accountingReport, String name)
throws AxelorException {
return ReportFactory.createReport(
String.format(IReport.ACCOUNTING_REPORT_TYPE, accountingReport.getTypeSelect()),
name + "-${date}")
.addParam("AccountingReportId", accountingReport.getId())
.addParam("Locale", ReportSettings.getPrintingLocale(null))
.addFormat(accountingReport.getExportTypeSelect())
.toAttach(accountingReport)
.generate()
.getFileLink();
}
public boolean isThereTooManyLines(AccountingReport accountingReport) throws AxelorException {
AccountConfig accountConfig =
Beans.get(AccountConfigService.class).getAccountConfig(accountingReport.getCompany());
Integer lineMinBeforeLongReportGenerationMessageNumber =
accountConfig.getLineMinBeforeLongReportGenerationMessageNumber();
if (lineMinBeforeLongReportGenerationMessageNumber != null
&& lineMinBeforeLongReportGenerationMessageNumber > 0) {
Integer typeSelect = accountingReport.getTypeSelect();
long count = 0;
if (typeSelect > 0 && typeSelect <= AccountingReportRepository.REPORT_GENERAL_LEDGER2) {
count =
Beans.get(MoveLineRepository.class)
.all()
.filter(this.getMoveLineList(accountingReport))
.count();
} else if (typeSelect == AccountingReportRepository.REPORT_VAT_STATEMENT_RECEIVED) {
count =
Beans.get(TaxPaymentMoveLineRepository.class)
.all()
.filter(this.getTaxPaymentMoveLineList(accountingReport))
.count();
} else if (typeSelect == AccountingReportRepository.REPORT_ACQUISITIONS) {
count =
Beans.get(FixedAssetRepository.class)
.all()
.filter(this.getFixedAssetList(accountingReport))
.count();
count +=
JPA.em()
.createQuery(
"Select invoiceLine FROM InvoiceLine invoiceLine LEFT JOIN FixedAsset fixedAsset on fixedAsset.invoiceLine = invoiceLine.id WHERE invoiceLine.fixedAssets = true and fixedAsset.invoiceLine is null ")
.getResultList()
.size();
} else if (typeSelect == AccountingReportRepository.REPORT_GROSS_VALUES_AND_DEPRECIATION) {
count =
Beans.get(FixedAssetRepository.class)
.all()
.filter(this.getFixedAssetList(accountingReport))
.count();
} else if (typeSelect == AccountingReportRepository.REPORT_ANALYTIC_BALANCE) {
count =
Beans.get(AnalyticMoveLineRepository.class)
.all()
.filter(this.getAnalyticMoveLineList(accountingReport))
.count();
} else {
return false;
}
return count > lineMinBeforeLongReportGenerationMessageNumber;
} else {
return false;
}
}
protected String getAnalyticMoveLineList(AccountingReport accountingReport) {
this.buildAnalyticMoveLineQuery(accountingReport);
return this.buildDomainFromQuery();
}
protected void buildAnalyticMoveLineQuery(AccountingReport accountingReport) {
this.initQuery();
this.addParams("self.moveLine.move.companyCurrency = ?%d", accountingReport.getCurrency());
if (accountingReport.getJournal() != null) {
this.addParams("self.moveLine.move.journal = ?%d", accountingReport.getJournal());
}
if (accountingReport.getDateFrom() != null) {
this.addParams("self.date >= ?%d", accountingReport.getDateFrom());
}
if (accountingReport.getDateTo() != null) {
this.addParams("self.date <= ?%d", accountingReport.getDateTo());
}
this.addParams("self.date <= ?%d", accountingReport.getDate());
if (accountingReport.getAnalyticJournal() != null) {
this.addParams("self.analyticJournal = ?%d", accountingReport.getAnalyticJournal());
}
this.addParams("self.typeSelect = ?%d", AnalyticMoveLineRepository.STATUS_REAL_ACCOUNTING);
this.addParams("self.moveLine.move.ignoreInAccountingOk = 'false'");
this.addParams(
"(self.moveLine.move.statusSelect = "
+ MoveRepository.STATUS_DAYBOOK
+ " OR self.moveLine.move.statusSelect = "
+ MoveRepository.STATUS_VALIDATED
+ ")");
log.debug("Query : {}", this.query);
}
protected String getFixedAssetList(AccountingReport accountingReport) {
this.buildFixedAssetQuery(accountingReport);
return this.buildDomainFromQuery();
}
protected void buildFixedAssetQuery(AccountingReport accountingReport) {
this.initQuery();
this.addParams(
"(self.statusSelect = "
+ FixedAssetRepository.STATUS_VALIDATED
+ " OR self.statusSelect = "
+ FixedAssetRepository.STATUS_DEPRECIATED
+ ")");
if (accountingReport.getTypeSelect() == AccountingReportRepository.REPORT_ACQUISITIONS) {
if (accountingReport.getDateFrom() != null) {
this.addParams("self.acquisitionDate >= ?%d", accountingReport.getDateFrom());
}
if (accountingReport.getDateTo() != null) {
this.addParams("self.acquisitionDate <= ?%d", accountingReport.getDateTo());
}
}
if (accountingReport.getTypeSelect()
== AccountingReportRepository.REPORT_GROSS_VALUES_AND_DEPRECIATION) {
this.query += " OR ( self.statusSelect = " + FixedAssetRepository.STATUS_TRANSFERRED + " ";
if (accountingReport.getDateFrom() != null) {
this.addParams("self.disposalDate >= ?%d", accountingReport.getDateFrom());
}
if (accountingReport.getDateTo() != null) {
this.addParams("self.disposalDate <= ?%d", accountingReport.getDateTo());
}
this.query += " ) ";
}
log.debug("Query : {}", this.query);
}
protected String getTaxPaymentMoveLineList(AccountingReport accountingReport) {
this.buildTaxPaymentQuery(accountingReport);
return this.buildDomainFromQuery();
}
protected String buildTaxPaymentQuery(AccountingReport accountingReport) {
this.initQuery();
if (accountingReport.getCompany() != null) {
this.addParams("self.moveLine.move.company = ?%d", accountingReport.getCompany());
}
if (accountingReport.getCurrency() != null) {
this.addParams("self.moveLine.move.companyCurrency = ?%d", accountingReport.getCurrency());
}
if (accountingReport.getDateFrom() != null) {
this.addParams("self.moveLine.date >= ?%d", accountingReport.getDateFrom());
}
if (accountingReport.getDateTo() != null) {
this.addParams("self.moveLine.date <= ?%d", accountingReport.getDateTo());
}
this.addParams("self.moveLine.move.ignoreInAccountingOk = 'false'");
this.addParams(
"(self.moveLine.move.statusSelect = "
+ MoveRepository.STATUS_DAYBOOK
+ " OR self.moveLine.move.statusSelect = "
+ MoveRepository.STATUS_VALIDATED
+ ")");
this.addParams("self.originTaxLine.tax.typeSelect = ?%d", TaxRepository.TAX_TYPE_COLLECTION);
log.debug("Query : {}", this.query);
return this.query;
}
}

View File

@ -0,0 +1,39 @@
/*
* 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.account.service;
public class AccountingService {
private static boolean DEFAULT_UPDATE_CUSTOMER_ACCOUNT = true;
private static final ThreadLocal<Boolean> threadLocal = new ThreadLocal<Boolean>();
public static void setUpdateCustomerAccount(boolean updateCustomerAccount) {
threadLocal.set(updateCustomerAccount);
}
public static boolean getUpdateCustomerAccount() {
if (threadLocal.get() != null) {
return threadLocal.get();
}
return DEFAULT_UPDATE_CUSTOMER_ACCOUNT;
}
}

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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import com.axelor.meta.CallMethod;
import java.util.List;
public interface AccountingSituationService {
boolean checkAccountingSituationList(
List<AccountingSituation> accountingSituationList, Company company);
/**
* Creates unexisting accounting situations for a given partner. Created situations will be
* appended to the partner's AccountingSituationList
*
* @param partner Partner to create accounting situation for.
* @return The created accounting situations (which is the same as calling
* partner.getAccountingSituationList())
* @throws AxelorException In case of configuration issue
*/
List<AccountingSituation> createAccountingSituation(Partner partner) throws AxelorException;
AccountingSituation getAccountingSituation(Partner partner, Company company);
AccountingSituation createAccountingSituation(Partner partner, Company company)
throws AxelorException;
/**
* Automatically creates supplier/customer/employee accounts based on situation's company
* configuration.
*
* @param situation Situation on which accounts should be created.
*/
void createPartnerAccounts(AccountingSituation situation) throws AxelorException;
String createDomainForBankDetails(
AccountingSituation accountingSituation, boolean isInBankDetails);
void updateCustomerCredit(Partner partner) throws AxelorException;
/**
* Get customer account from accounting situation or account config.
*
* @param partner
* @param company
* @return
*/
Account getCustomerAccount(Partner partner, Company company) throws AxelorException;
/**
* Get supplier account from accounting situation or account config.
*
* @param partner
* @param company
* @return
*/
Account getSupplierAccount(Partner partner, Company company) throws AxelorException;
/**
* Get employee account from accounting situation or account config.
*
* @param partner
* @param company
* @return
*/
Account getEmployeeAccount(Partner partner, Company company) throws AxelorException;
/**
* Return bank details for sales to <code>partner</code> (took from SaleOrder.xml).
*
* @param company
* @param partner
* @return
*/
@CallMethod
BankDetails getCompanySalesBankDetails(Company company, Partner partner);
}

View File

@ -0,0 +1,496 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.AccountType;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.account.db.PaymentMode;
import com.axelor.apps.account.db.repo.AccountConfigRepository;
import com.axelor.apps.account.db.repo.AccountRepository;
import com.axelor.apps.account.db.repo.AccountTypeRepository;
import com.axelor.apps.account.db.repo.AccountingSituationRepository;
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.payment.PaymentModeService;
import com.axelor.apps.base.db.AppAccount;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Sequence;
import com.axelor.apps.base.db.repo.AppAccountRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.apps.tool.StringTool;
import com.axelor.common.StringUtils;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class AccountingSituationServiceImpl implements AccountingSituationService {
protected AccountConfigService accountConfigService;
protected SequenceService sequenceService;
protected AccountingSituationRepository accountingSituationRepo;
@Inject
public AccountingSituationServiceImpl(
AccountConfigService accountConfigService,
SequenceService sequenceService,
AccountingSituationRepository accountingSituationRepo) {
this.accountConfigService = accountConfigService;
this.sequenceService = sequenceService;
this.accountingSituationRepo = accountingSituationRepo;
}
@Override
public boolean checkAccountingSituationList(
List<AccountingSituation> accountingSituationList, Company company) {
if (accountingSituationList != null) {
for (AccountingSituation accountingSituation : accountingSituationList) {
if (accountingSituation.getCompany().equals(company)) {
return true;
}
}
}
return false;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public List<AccountingSituation> createAccountingSituation(Partner partner)
throws AxelorException {
Set<Company> companySet = partner.getCompanySet();
if (companySet != null) {
for (Company company : companySet) {
if (!checkAccountingSituationList(partner.getAccountingSituationList(), company)) {
createAccountingSituation(partner, company);
}
}
}
return partner.getAccountingSituationList();
}
@Override
@Transactional(rollbackOn = {Exception.class})
public AccountingSituation createAccountingSituation(Partner partner, Company company)
throws AxelorException {
AccountingSituation accountingSituation = new AccountingSituation();
accountingSituation.setCompany(company);
partner.addCompanySetItem(company);
PaymentMode inPaymentMode = partner.getInPaymentMode();
PaymentMode outPaymentMode = partner.getOutPaymentMode();
BankDetails defaultBankDetails = company.getDefaultBankDetails();
if (inPaymentMode != null) {
List<BankDetails> authorizedInBankDetails =
Beans.get(PaymentModeService.class).getCompatibleBankDetailsList(inPaymentMode, company);
if (authorizedInBankDetails.contains(defaultBankDetails)) {
accountingSituation.setCompanyInBankDetails(defaultBankDetails);
}
}
if (outPaymentMode != null) {
List<BankDetails> authorizedOutBankDetails =
Beans.get(PaymentModeService.class).getCompatibleBankDetailsList(outPaymentMode, company);
if (authorizedOutBankDetails.contains(defaultBankDetails)) {
accountingSituation.setCompanyOutBankDetails(defaultBankDetails);
}
}
Account acc = this.createPartnerAccount(partner, company);
AccountConfig accountConfig = Beans.get(AccountConfigService.class).getAccountConfig(company);
accountingSituation.setInvoiceAutomaticMail(accountConfig.getInvoiceAutomaticMail());
accountingSituation.setInvoiceMessageTemplate(accountConfig.getInvoiceMessageTemplate());
if (acc != null) {
if (partner.getIsCustomer()) {
accountingSituation.setCustomerAccount(acc);
} else if (partner.getIsSupplier()) {
accountingSituation.setSupplierAccount(acc);
}
}
partner.addAccountingSituationListItem(accountingSituation);
return accountingSituationRepo.save(accountingSituation);
}
// sophal creating account
@Transactional
private Account createPartnerAccount(Partner partner, Company company) {
Account sAccount = new Account();
AppAccount appAccount = Beans.get(AppAccountService.class).getAppAccount();
int partnerCode = appAccount.getSupplierCodeSequence() + 1;
appAccount.setSupplierCodeSequence(partnerCode);
String accounString = "Fournisseurs";
if (partner.getIsCustomer()) {
accounString = "Clients";
partnerCode = appAccount.getClientCodeSequence() + 1;
appAccount.setClientCodeSequence(partnerCode);
}
AccountType accountType = Beans.get(AccountTypeRepository.class).findByName(accounString);
Account parenAccount = Beans.get(AccountRepository.class).findByCode("0");
sAccount.setAccountType(accountType);
sAccount.setCode(String.valueOf(partnerCode));
sAccount.setName(partner.getName());
sAccount.setReconcileOk(true);
sAccount.setUseForPartnerBalance(true);
sAccount.setCompany(company);
sAccount.setParentAccount(parenAccount);
Beans.get(AppAccountRepository.class).save(appAccount);
return sAccount;
}
@Override
public AccountingSituation getAccountingSituation(Partner partner, Company company) {
if (partner == null || partner.getAccountingSituationList() == null) {
return null;
}
for (AccountingSituation accountingSituation : partner.getAccountingSituationList()) {
if (accountingSituation.getCompany() != null
&& accountingSituation.getCompany().equals(company)) {
return accountingSituation;
}
}
return null;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void createPartnerAccounts(AccountingSituation situation) throws AxelorException {
AccountConfig accountConfig = situation.getCompany().getAccountConfig();
int creationMode;
if (accountConfig == null
|| (creationMode = accountConfig.getPartnerAccountGenerationModeSelect())
== AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_NONE) {
// Ignore even if account config is null since this means no automatic creation
return;
}
createCustomerAccount(accountConfig, situation, creationMode);
createSupplierAccount(accountConfig, situation, creationMode);
createEmployeeAccount(accountConfig, situation, creationMode);
}
protected void createCustomerAccount(
AccountConfig accountConfig, AccountingSituation situation, int creationMode)
throws AxelorException {
Partner partner = situation.getPartner();
if (partner.getIsCustomer() == Boolean.FALSE || situation.getCustomerAccount() != null) return;
if (accountConfig.getCustomerAccount() == null) {
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNT_CUSTOMER_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
situation.getCompany().getName());
}
final String accountCode;
if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_PREFIX) {
final String prefix = accountConfig.getCustomerAccountPrefix();
if (StringUtils.isBlank(prefix)) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_1),
situation.getCompany().getName());
}
accountCode = getPrefixedAccountCode(prefix, partner);
} else if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_SEQUENCE) {
final Sequence sequence = accountConfig.getCustomerAccountSequence();
if (sequence == null) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_2),
situation.getCompany().getName());
}
accountCode = sequenceService.getSequenceNumber(sequence);
} else {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_3),
situation.getCompany().getName());
}
Account account = new Account();
account.setName(partner.getFullName());
account.setCode(accountCode);
account.setParentAccount(accountConfig.getCustomerAccount());
account.setAccountType(accountConfig.getCustomerAccount().getAccountType());
account.setReconcileOk(true);
account.setCompany(situation.getCompany());
account.setUseForPartnerBalance(true);
account.setCompatibleAccountSet(new HashSet<>());
situation.setCustomerAccount(account);
}
protected void createSupplierAccount(
AccountConfig accountConfig, AccountingSituation situation, int creationMode)
throws AxelorException {
Partner partner = situation.getPartner();
if (partner.getIsSupplier() == Boolean.FALSE || situation.getSupplierAccount() != null) return;
if (accountConfig.getSupplierAccount() == null) {
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNT_CUSTOMER_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
situation.getCompany().getName());
}
final String accountCode;
if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_PREFIX) {
final String prefix = accountConfig.getSupplierAccountPrefix();
if (StringUtils.isBlank(prefix)) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_4),
situation.getCompany().getName());
}
accountCode = getPrefixedAccountCode(prefix, partner);
} else if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_SEQUENCE) {
final Sequence sequence = accountConfig.getSupplierAccountSequence();
if (sequence == null) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_5),
situation.getCompany().getName());
}
accountCode = sequenceService.getSequenceNumber(sequence);
} else {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_3),
situation.getCompany().getName());
}
Account account = new Account();
account.setName(partner.getFullName());
account.setCode(accountCode);
account.setParentAccount(accountConfig.getSupplierAccount());
account.setAccountType(accountConfig.getSupplierAccount().getAccountType());
account.setReconcileOk(true);
account.setCompany(situation.getCompany());
account.setUseForPartnerBalance(true);
account.setCompatibleAccountSet(new HashSet<>());
situation.setSupplierAccount(account);
}
protected void createEmployeeAccount(
AccountConfig accountConfig, AccountingSituation situation, int creationMode)
throws AxelorException {
Partner partner = situation.getPartner();
if (partner.getIsEmployee() == Boolean.FALSE || situation.getEmployeeAccount() != null) return;
if (accountConfig.getEmployeeAccount() == null) {
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNT_CONFIG_40),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
situation.getCompany().getName());
}
final String accountCode;
if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_PREFIX) {
final String prefix = accountConfig.getEmployeeAccountPrefix();
if (StringUtils.isBlank(prefix)) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_6),
situation.getCompany().getName());
}
accountCode = getPrefixedAccountCode(prefix, partner);
} else if (creationMode == AccountConfigRepository.AUTOMATIC_ACCOUNT_CREATION_SEQUENCE) {
final Sequence sequence = accountConfig.getEmployeeAccountSequence();
if (sequence == null) {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_7),
situation.getCompany().getName());
}
accountCode = sequenceService.getSequenceNumber(sequence);
} else {
throw new AxelorException(
situation,
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.ACCOUNTING_SITUATION_3),
situation.getCompany().getName());
}
Account account = new Account();
account.setName(partner.getFullName());
account.setCode(accountCode);
account.setParentAccount(accountConfig.getEmployeeAccount());
account.setAccountType(accountConfig.getEmployeeAccount().getAccountType());
account.setReconcileOk(true);
account.setCompany(situation.getCompany());
account.setUseForPartnerBalance(true);
account.setCompatibleAccountSet(new HashSet<>());
situation.setEmployeeAccount(account);
}
/**
* Normalize partner's fullname to be usable as an account name. Name is appended to prefix, then
* uppercased and unaccented
*
* @param prefix Prefix to prepend to the generated account code
* @param partner Partner to generate account code for
* @return The generated account code.
*/
protected String getPrefixedAccountCode(String prefix, Partner partner) {
return (prefix + StringUtils.stripAccent(partner.getFullName()))
.toUpperCase()
.replaceAll("[^A-Z]", "");
}
/**
* Creates the domain for the bank details in Accounting Situation
*
* @param accountingSituation
* @param isInBankDetails true if the field is companyInBankDetails false if the field is
* companyOutBankDetails
* @return the domain of the bank details field
*/
@Override
public String createDomainForBankDetails(
AccountingSituation accountingSituation, boolean isInBankDetails) {
String domain = "";
List<BankDetails> authorizedBankDetails;
if (accountingSituation.getPartner() != null) {
if (isInBankDetails) {
authorizedBankDetails =
Beans.get(PaymentModeService.class)
.getCompatibleBankDetailsList(
accountingSituation.getPartner().getInPaymentMode(),
accountingSituation.getCompany());
} else {
authorizedBankDetails =
Beans.get(PaymentModeService.class)
.getCompatibleBankDetailsList(
accountingSituation.getPartner().getOutPaymentMode(),
accountingSituation.getCompany());
}
String idList = StringTool.getIdListString(authorizedBankDetails);
if (idList.equals("")) {
return domain;
}
domain = "self.id IN (" + idList + ") AND self.active = true";
}
return domain;
}
@Override
public void updateCustomerCredit(Partner partner) throws AxelorException {
// Nothing to do if the supplychain module is not loaded.
}
@Override
public Account getCustomerAccount(Partner partner, Company company) throws AxelorException {
Account account = null;
AccountingSituation accountingSituation = getAccountingSituation(partner, company);
if (accountingSituation != null) {
account = accountingSituation.getCustomerAccount();
}
if (account == null) {
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
account = accountConfigService.getCustomerAccount(accountConfig);
}
return account;
}
@Override
public Account getSupplierAccount(Partner partner, Company company) throws AxelorException {
Account account = null;
AccountingSituation accountingSituation = getAccountingSituation(partner, company);
if (accountingSituation != null) {
account = accountingSituation.getSupplierAccount();
}
if (account == null) {
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
account = accountConfigService.getSupplierAccount(accountConfig);
}
return account;
}
@Override
public Account getEmployeeAccount(Partner partner, Company company) throws AxelorException {
Account account = null;
AccountingSituation accountingSituation = getAccountingSituation(partner, company);
if (accountingSituation != null) {
account = accountingSituation.getEmployeeAccount();
}
if (account == null) {
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
account = accountConfigService.getEmployeeAccount(accountConfig);
}
return account;
}
@Override
public BankDetails getCompanySalesBankDetails(Company company, Partner partner) {
AccountingSituation situation = getAccountingSituation(partner, company);
if (situation != null
&& situation.getCompanyInBankDetails() != null
&& situation.getCompanyInBankDetails().getActive()) {
return situation.getCompanyInBankDetails();
}
return company.getDefaultBankDetails();
}
}

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.account.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.Umr;
import com.axelor.apps.base.service.AddressServiceImpl;
import com.axelor.db.JPA;
public class AddressServiceAccountImpl extends AddressServiceImpl {
static {
registerCheckUsedFunc(AddressServiceAccountImpl::checkAddressUsedAccount);
}
private static boolean checkAddressUsedAccount(Long addressId) {
return JPA.all(Invoice.class).filter("self.address.id = ?1", addressId).fetchOne() != null
|| JPA.all(Umr.class).filter("self.debtorAddress.id = ?1", addressId).fetchOne() != null;
}
}

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.account.service;
import com.axelor.apps.account.db.AnalyticDistributionLine;
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Product;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
public interface AnalyticMoveLineService {
public BigDecimal computeAmount(AnalyticMoveLine analyticMoveLine);
public List<AnalyticMoveLine> generateLines(
AnalyticDistributionTemplate analyticDistributionTemplate,
BigDecimal total,
int typeSelect,
LocalDate date);
public AnalyticDistributionTemplate getAnalyticDistributionTemplate(
Partner partner, Product product, Company company);
public void updateAnalyticMoveLine(
AnalyticMoveLine analyticMoveLine, BigDecimal total, LocalDate date);
public boolean validateLines(List<AnalyticDistributionLine> analyticDistributionLineList);
}

View File

@ -0,0 +1,156 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.AnalyticAxis;
import com.axelor.apps.account.db.AnalyticDistributionLine;
import com.axelor.apps.account.db.AnalyticDistributionTemplate;
import com.axelor.apps.account.db.AnalyticJournal;
import com.axelor.apps.account.db.AnalyticMoveLine;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.base.db.AppAccount;
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.AppAccountRepository;
import com.google.inject.Inject;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AnalyticMoveLineServiceImpl implements AnalyticMoveLineService {
protected AppAccountService appAccountService;
protected AccountManagementServiceAccountImpl accountManagementServiceAccountImpl;
@Inject
public AnalyticMoveLineServiceImpl(
AppAccountService appAccountService,
AccountManagementServiceAccountImpl accountManagementServiceAccountImpl) {
this.appAccountService = appAccountService;
this.accountManagementServiceAccountImpl = accountManagementServiceAccountImpl;
}
@Override
public BigDecimal computeAmount(AnalyticMoveLine analyticMoveLine) {
return analyticMoveLine
.getPercentage()
.multiply(analyticMoveLine.getOriginalPieceAmount())
.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
}
@Override
public List<AnalyticMoveLine> generateLines(
AnalyticDistributionTemplate analyticDistributionTemplate,
BigDecimal total,
int typeSelect,
LocalDate date) {
List<AnalyticMoveLine> analyticMoveLineList = new ArrayList<AnalyticMoveLine>();
if (analyticDistributionTemplate != null) {
for (AnalyticDistributionLine analyticDistributionLine :
analyticDistributionTemplate.getAnalyticDistributionLineList()) {
analyticMoveLineList.add(
this.createAnalyticMoveLine(analyticDistributionLine, total, typeSelect, date));
}
}
return analyticMoveLineList;
}
@Override
public AnalyticDistributionTemplate getAnalyticDistributionTemplate(
Partner partner, Product product, Company company) {
AppAccount appAccount = appAccountService.getAppAccount();
if (appAccount.getAnalyticDistributionTypeSelect()
== AppAccountRepository.DISTRIBUTION_TYPE_PARTNER
&& partner != null) {
return partner.getAnalyticDistributionTemplate();
} else if (appAccount.getAnalyticDistributionTypeSelect()
== AppAccountRepository.DISTRIBUTION_TYPE_PRODUCT) {
return accountManagementServiceAccountImpl.getAnalyticDistributionTemplate(product, company);
}
return null;
}
public AnalyticMoveLine createAnalyticMoveLine(
AnalyticDistributionLine analyticDistributionLine,
BigDecimal total,
int typeSelect,
LocalDate date) {
AnalyticMoveLine analyticMoveLine = new AnalyticMoveLine();
analyticMoveLine.setOriginalPieceAmount(total);
analyticMoveLine.setAnalyticAccount(analyticDistributionLine.getAnalyticAccount());
analyticMoveLine.setAnalyticAxis(analyticDistributionLine.getAnalyticAxis());
analyticMoveLine.setAnalyticJournal(analyticDistributionLine.getAnalyticJournal());
AnalyticJournal analyticJournal = analyticDistributionLine.getAnalyticJournal();
Company company = analyticJournal == null ? null : analyticJournal.getCompany();
if (company != null) {
analyticMoveLine.setCurrency(company.getCurrency());
}
analyticMoveLine.setDate(date);
analyticMoveLine.setPercentage(analyticDistributionLine.getPercentage());
analyticMoveLine.setAmount(computeAmount(analyticMoveLine));
analyticMoveLine.setTypeSelect(typeSelect);
return analyticMoveLine;
}
@Override
public void updateAnalyticMoveLine(
AnalyticMoveLine analyticMoveLine, BigDecimal total, LocalDate date) {
analyticMoveLine.setOriginalPieceAmount(total);
analyticMoveLine.setAmount(computeAmount(analyticMoveLine));
analyticMoveLine.setDate(date);
}
@Override
public boolean validateLines(List<AnalyticDistributionLine> analyticDistributionLineList) {
if (analyticDistributionLineList != null) {
Map<AnalyticAxis, BigDecimal> map = new HashMap<AnalyticAxis, BigDecimal>();
for (AnalyticDistributionLine analyticDistributionLine : analyticDistributionLineList) {
if (map.containsKey(analyticDistributionLine.getAnalyticAxis())) {
map.put(
analyticDistributionLine.getAnalyticAxis(),
map.get(analyticDistributionLine.getAnalyticAxis())
.add(analyticDistributionLine.getPercentage()));
} else {
map.put(
analyticDistributionLine.getAnalyticAxis(), analyticDistributionLine.getPercentage());
}
}
for (AnalyticAxis analyticAxis : map.keySet()) {
if (map.get(analyticAxis).compareTo(new BigDecimal(100)) > 0) {
return false;
}
}
}
return true;
}
}

View File

@ -0,0 +1,210 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.AccountManagement;
import com.axelor.apps.account.db.AccountingSituation;
import com.axelor.apps.account.db.PaymentMode;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.db.repo.PaymentModeRepository;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.payment.PaymentModeService;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.service.BankDetailsServiceImpl;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.tool.StringTool;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class BankDetailsServiceAccountImpl extends BankDetailsServiceImpl {
/**
* In this implementation, we use the O2M in payment mode.
*
* @param company
* @param paymentMode
* @return
* @throws AxelorException
*/
@Override
public String createCompanyBankDetailsDomain(
Partner partner, Company company, PaymentMode paymentMode, Integer operationTypeSelect)
throws AxelorException {
if (!Beans.get(AppBaseService.class).getAppBase().getManageMultiBanks()) {
return super.createCompanyBankDetailsDomain(
partner, company, paymentMode, operationTypeSelect);
} else {
if (partner != null) {
partner = Beans.get(PartnerRepository.class).find(partner.getId());
}
List<BankDetails> authorizedBankDetails = new ArrayList<>();
if (partner != null
&& partner.getFactorizedCustomer()
&& operationTypeSelect != null
&& (operationTypeSelect.intValue() == InvoiceRepository.OPERATION_TYPE_CLIENT_SALE
|| operationTypeSelect.intValue()
== InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND)) {
authorizedBankDetails = createCompanyBankDetailsDomainFromFactorPartner(company);
} else {
if (paymentMode == null) {
return "self.id IN (0)";
}
List<AccountManagement> accountManagementList = paymentMode.getAccountManagementList();
authorizedBankDetails = new ArrayList<>();
for (AccountManagement accountManagement : accountManagementList) {
if (accountManagement.getCompany() != null
&& accountManagement.getCompany().equals(company)) {
authorizedBankDetails.add(accountManagement.getBankDetails());
}
}
}
if (authorizedBankDetails.isEmpty()) {
return "self.id IN (0)";
} else {
return "self.id IN ("
+ StringTool.getIdListString(authorizedBankDetails)
+ ") AND self.active = true";
}
}
}
private List<BankDetails> createCompanyBankDetailsDomainFromFactorPartner(Company company)
throws AxelorException {
AccountConfig accountConfig = Beans.get(AccountConfigService.class).getAccountConfig(company);
List<BankDetails> bankDetailsList = accountConfig.getFactorPartner().getBankDetailsList();
return bankDetailsList
.stream()
.filter(bankDetails -> bankDetails.getActive())
.collect(Collectors.toList());
}
/**
* Find a default bank details.
*
* @param company
* @param paymentMode
* @param partner
* @return the default bank details in accounting situation if it is active and allowed by the
* payment mode, or an authorized bank details if he is the only one authorized.
* @throws AxelorException
*/
@Override
public BankDetails getDefaultCompanyBankDetails(
Company company, PaymentMode paymentMode, Partner partner, Integer operationTypeSelect)
throws AxelorException {
if (!Beans.get(AppBaseService.class).getAppBase().getManageMultiBanks()) {
return super.getDefaultCompanyBankDetails(company, paymentMode, partner, operationTypeSelect);
} else {
if (partner != null
&& partner.getFactorizedCustomer()
&& operationTypeSelect != null
&& (operationTypeSelect.intValue() == InvoiceRepository.OPERATION_TYPE_CLIENT_SALE
|| operationTypeSelect.intValue()
== InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND)) {
return getDefaultCompanyBankDetailsFromFactorPartner(company);
} else {
if (paymentMode == null) {
return null;
}
BankDetails candidateBankDetails =
getDefaultCompanyBankDetailsFromPartner(company, paymentMode, partner);
List<BankDetails> authorizedBankDetails =
Beans.get(PaymentModeService.class).getCompatibleBankDetailsList(paymentMode, company);
if (candidateBankDetails != null
&& authorizedBankDetails.contains(candidateBankDetails)
&& candidateBankDetails.getActive()) {
return candidateBankDetails;
}
// we did not find a bank details in accounting situation
else {
if (authorizedBankDetails.size() == 1) {
return authorizedBankDetails.get(0);
}
}
}
return null;
}
}
private BankDetails getDefaultCompanyBankDetailsFromFactorPartner(Company company)
throws AxelorException {
AccountConfig accountConfig = Beans.get(AccountConfigService.class).getAccountConfig(company);
if (accountConfig.getFactorPartner() == null) {
return null;
}
List<BankDetails> bankDetailsList = accountConfig.getFactorPartner().getBankDetailsList();
return bankDetailsList
.stream()
.filter(bankDetails -> bankDetails.getIsDefault())
.findFirst()
.orElse(null);
}
/**
* Looks for the bank details in accounting situation.
*
* @param company
* @param paymentMode
* @param partner
* @return The bank details corresponding to the partner and the company with the right payment
* mode null if the partner is null or the accounting situation empty
*/
protected BankDetails getDefaultCompanyBankDetailsFromPartner(
Company company, PaymentMode paymentMode, Partner partner) {
if (partner == null) {
return null;
}
AccountingSituation accountingSituation =
Beans.get(AccountingSituationService.class).getAccountingSituation(partner, company);
if (accountingSituation == null) {
return null;
}
BankDetails candidateBankDetails = null;
if (paymentMode.getInOutSelect() == PaymentModeRepository.IN) {
candidateBankDetails = accountingSituation.getCompanyInBankDetails();
} else if (paymentMode.getInOutSelect() == PaymentModeRepository.OUT) {
candidateBankDetails = accountingSituation.getCompanyOutBankDetails();
}
return candidateBankDetails;
}
}

View File

@ -0,0 +1,238 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Budget;
import com.axelor.apps.account.db.BudgetDistribution;
import com.axelor.apps.account.db.BudgetLine;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.repo.BudgetDistributionRepository;
import com.axelor.apps.account.db.repo.BudgetLineRepository;
import com.axelor.apps.account.db.repo.BudgetRepository;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class BudgetService {
protected BudgetLineRepository budgetLineRepository;
protected BudgetRepository budgetRepository;
@Inject
public BudgetService(
BudgetLineRepository budgetLineRepository, BudgetRepository budgetRepository) {
this.budgetLineRepository = budgetLineRepository;
this.budgetRepository = budgetRepository;
}
public BigDecimal compute(Budget budget) {
BigDecimal total = BigDecimal.ZERO;
if (budget.getBudgetLineList() != null) {
for (BudgetLine budgetLine : budget.getBudgetLineList()) {
total = total.add(budgetLine.getAmountExpected());
}
}
return total;
}
@Transactional
public BigDecimal computeTotalAmountRealized(Budget budget) {
List<BudgetLine> budgetLineList = budget.getBudgetLineList();
if (budgetLineList == null) {
return BigDecimal.ZERO;
}
BigDecimal totalAmountRealized =
budgetLineList
.stream()
.map(BudgetLine::getAmountRealized)
.reduce(BigDecimal.ZERO, BigDecimal::add);
budget.setTotalAmountRealized(totalAmountRealized);
return totalAmountRealized;
}
@Transactional
public List<BudgetLine> updateLines(Budget budget) {
if (budget.getBudgetLineList() != null && !budget.getBudgetLineList().isEmpty()) {
for (BudgetLine budgetLine : budget.getBudgetLineList()) {
budgetLine.setAmountRealized(BigDecimal.ZERO);
}
List<BudgetDistribution> budgetDistributionList =
Beans.get(BudgetDistributionRepository.class)
.all()
.filter(
"self.budget.id = ?1 AND (self.invoiceLine.invoice.statusSelect = ?2 OR self.invoiceLine.invoice.statusSelect = ?3)",
budget.getId(),
InvoiceRepository.STATUS_VALIDATED,
InvoiceRepository.STATUS_VENTILATED)
.fetch();
for (BudgetDistribution budgetDistribution : budgetDistributionList) {
Optional<LocalDate> optionaldate = getDate(budgetDistribution);
optionaldate.ifPresent(
date -> {
for (BudgetLine budgetLine : budget.getBudgetLineList()) {
LocalDate fromDate = budgetLine.getFromDate();
LocalDate toDate = budgetLine.getToDate();
if ((fromDate.isBefore(date) || fromDate.isEqual(date))
&& (toDate.isAfter(date) || toDate.isEqual(date))) {
budgetLine.setAmountRealized(
budgetLine.getAmountRealized().add(budgetDistribution.getAmount()));
break;
}
}
});
}
}
return budget.getBudgetLineList();
}
/**
* @param budgetDistribution
* @return returns an {@code Optional} because in some cases the child implementations can return
* a null value.
*/
protected Optional<LocalDate> getDate(BudgetDistribution budgetDistribution) {
Invoice invoice = budgetDistribution.getInvoiceLine().getInvoice();
LocalDate invoiceDate = invoice.getInvoiceDate();
if (invoiceDate != null) {
return Optional.of(invoiceDate);
}
return Optional.of(invoice.getValidatedDate());
}
public List<BudgetLine> generatePeriods(Budget budget) throws AxelorException {
if (budget.getBudgetLineList() != null && !budget.getBudgetLineList().isEmpty()) {
List<BudgetLine> budgetLineList = budget.getBudgetLineList();
budgetLineList.clear();
}
List<BudgetLine> budgetLineList = new ArrayList<BudgetLine>();
Integer duration = budget.getPeriodDurationSelect();
LocalDate fromDate = budget.getFromDate();
LocalDate toDate = budget.getToDate();
LocalDate budgetLineToDate = fromDate;
Integer budgetLineNumber = 1;
int c = 0;
int loopLimit = 1000;
while (budgetLineToDate.isBefore(toDate)) {
if (budgetLineNumber != 1) fromDate = fromDate.plusMonths(duration);
if (c >= loopLimit) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY, I18n.get(IExceptionMessage.BUDGET_1));
}
c += 1;
budgetLineToDate = fromDate.plusMonths(duration).minusDays(1);
if (budgetLineToDate.isAfter(toDate)) budgetLineToDate = toDate;
if (fromDate.isAfter(toDate)) continue;
BudgetLine budgetLine = new BudgetLine();
budgetLine.setFromDate(fromDate);
budgetLine.setToDate(budgetLineToDate);
budgetLine.setBudget(budget);
budgetLine.setAmountExpected(budget.getAmountForGeneration());
budgetLineList.add(budgetLine);
budgetLineNumber++;
}
return budgetLineList;
}
public void checkSharedDates(Budget budget) throws AxelorException {
if (budget.getBudgetLineList() == null) {
return;
}
List<BudgetLine> budgetLineList = budget.getBudgetLineList();
for (int i = 0; i < budgetLineList.size() - 1; i++) {
BudgetLine budgetLineA = budgetLineList.get(i);
LocalDate fromDateA = budgetLineA.getFromDate();
LocalDate toDateA = budgetLineA.getToDate();
for (int j = i + 1; j < budgetLineList.size(); j++) {
BudgetLine budgetLineB = budgetLineList.get(j);
LocalDate fromDateB = budgetLineB.getFromDate();
LocalDate toDateB = budgetLineB.getToDate();
if (fromDateA.equals(fromDateB) || toDateA.equals(toDateB)) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get("Two or more budget lines share dates"));
}
if (fromDateA.isBefore(fromDateB) && (!toDateA.isBefore(fromDateB))) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get("Two or more budget lines share dates"));
}
if (fromDateA.isAfter(fromDateB) && (!fromDateA.isAfter(toDateB))) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get("Two or more budget lines share dates"));
}
}
}
}
@Transactional
public void validate(Budget budget) {
budget.setStatusSelect(BudgetRepository.STATUS_VALIDATED);
}
@Transactional
public void draft(Budget budget) {
budget.setStatusSelect(BudgetRepository.STATUS_DRAFT);
}
public void updateBudgetLinesFromInvoice(Invoice invoice) {
List<InvoiceLine> invoiceLineList = invoice.getInvoiceLineList();
if (invoiceLineList == null) {
return;
}
invoiceLineList
.stream()
.filter(invoiceLine -> invoiceLine.getBudgetDistributionList() != null)
.flatMap(x -> x.getBudgetDistributionList().stream())
.forEach(
budgetDistribution -> {
Budget budget = budgetDistribution.getBudget();
updateLines(budget);
computeTotalAmountRealized(budget);
});
}
}

View File

@ -0,0 +1,150 @@
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.CashInventory;
import com.axelor.apps.account.db.CashInventoryLine;
import com.axelor.apps.account.db.CashRegister;
import com.axelor.apps.account.db.repo.CashDenominationRepository;
import com.axelor.apps.account.db.repo.CashInventoryRepository;
import com.axelor.apps.account.db.repo.CashRegisterRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.auth.AuthUtils;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CashInventoryService {
private SequenceService sequenceService;
@Inject
public CashInventoryService(SequenceService sequenceService) {
this.sequenceService = sequenceService;
}
/**
* Initialize the theorical solde in words for a new cash inventory.
*
* @return the theorical solde in words as a BigDecimal
*/
public BigDecimal initThetoricalSolde() {
CashRegisterRepository casRegisterRepository = Beans.get(CashRegisterRepository.class);
CashRegister cashRegister = casRegisterRepository.all().order("-createdOn").fetchOne();
BigDecimal theoricalSolde = BigDecimal.ZERO;
if (cashRegister == null) {
theoricalSolde = BigDecimal.ZERO;
} else {
theoricalSolde = cashRegister.getTheoricalSolde();
}
return theoricalSolde;
}
/**
* Computes the totals for the cash inventory, including total bank notes, total
* coins, physical
* solde, and gap.
*
* @param cashInventory The cash inventory to compute totals for.
* @return A map containing the computed totals.
*/
public Map<String, BigDecimal> computeToTals(CashInventory cashInventory) {
HashMap<String, BigDecimal> map = new HashMap<>();
List<CashInventoryLine> cashInventoryLines = cashInventory.getCashInventoryLines();
BigDecimal theoricalSolde = cashInventory.getTheoricalSolde();
BigDecimal totalBankNotes = BigDecimal.ZERO;
BigDecimal totalCoins = BigDecimal.ZERO;
BigDecimal physicalSolde = BigDecimal.ZERO;
BigDecimal gap = BigDecimal.ZERO;
for (CashInventoryLine cashInventoryLine : cashInventoryLines) {
switch (cashInventoryLine.getCashDenomination().getTypeSelect()) {
case CashDenominationRepository.BANK_NOTE_TYPE:
totalBankNotes = totalBankNotes.add(cashInventoryLine.getTotalCashCount());
break;
case CashDenominationRepository.COINT_TYPE:
totalCoins = totalCoins.add(cashInventoryLine.getTotalCashCount());
break;
default:
totalBankNotes = BigDecimal.ZERO;
totalCoins = BigDecimal.ZERO;
break;
}
}
physicalSolde = physicalSolde.add(totalBankNotes).add(totalCoins);
gap = physicalSolde.subtract(theoricalSolde);
map.put("totalCoinsAmount", totalCoins);
map.put("totalBankNotesAmount", totalBankNotes);
map.put("totalCash", totalBankNotes);
map.put("physicalSolde", physicalSolde);
map.put("gap", gap);
return map;
}
public String getCashInventorySequence(CashInventory cashInventory) throws AxelorException {
Integer operationTypeSelect = cashInventory.getOperationTypeSelect();
Company company = cashInventory.getCompany();
String sequence = null;
if (operationTypeSelect != null) {
switch (operationTypeSelect) {
case 1: // Cash inventory daily
sequence = "CASH_INVENTORY_DAILY";
break;
case 2: // Cash inventory monthly
sequence = "CASH_INVENTORY_MONTHLY";
break;
case 3: // Cash inventory annual
sequence = "CASH_INVENTORY_ANNUAL";
break;
default:
sequence = "CASH_INVENTORY";
// Default case for other operation types
break;
}
} else {
sequence = "CASH_INVENTORY";
}
String ref = sequenceService.getSequenceNumber(sequence, company);
if (ref == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CASH_INVENTORY_MISSING_SEQUENCE),
company.getName());
} else {
return ref;
}
}
@Transactional(rollbackOn = {Exception.class})
public void approveCashInventory(CashInventory cashInventory) {
CashRegisterRepository casRegisterRepository = Beans.get(CashRegisterRepository.class);
CashRegister cashRegister = casRegisterRepository.all().order("-createdOn").fetchOne();
// cashRegister.setTheoricalSolde(cashInventory.getPhysicalSolde());
cashRegister.setPhysicalSolde(cashInventory.getPhysicalSolde());
cashInventory.setValdiatedByUser(AuthUtils.getUser());
cashInventory.setValidattionDate(LocalDateTime.now());
cashInventory.setStatusSelect(3);
Beans.get(CashInventoryRepository.class).save(cashInventory);
casRegisterRepository.save(cashRegister);
}
}

View File

@ -0,0 +1,214 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.ChequeRejection;
import com.axelor.apps.account.db.InterbankCodeLine;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.PaymentVoucher;
import com.axelor.apps.account.db.repo.ChequeRejectionRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
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.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
public class ChequeRejectionService {
protected MoveService moveService;
protected MoveLineService moveLineService;
protected SequenceService sequenceService;
protected AccountConfigService accountConfigService;
protected ChequeRejectionRepository chequeRejectionRepository;
@Inject
public ChequeRejectionService(
MoveService moveService,
MoveLineService moveLineService,
SequenceService sequenceService,
AccountConfigService accountConfigService,
ChequeRejectionRepository chequeRejectionRepository) {
this.moveService = moveService;
this.moveLineService = moveLineService;
this.sequenceService = sequenceService;
this.accountConfigService = accountConfigService;
this.chequeRejectionRepository = chequeRejectionRepository;
}
/**
* procédure de validation du rejet de chèque
*
* @param chequeRejection Un rejet de chèque brouillon
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public void validateChequeRejection(ChequeRejection chequeRejection) throws AxelorException {
Company company = chequeRejection.getCompany();
this.testCompanyField(company);
this.setSequence(chequeRejection);
Move move = this.createChequeRejectionMove(chequeRejection, company);
chequeRejection.setMove(move);
chequeRejection.setStatusSelect(ChequeRejectionRepository.STATUS_VALIDATED);
chequeRejectionRepository.save(chequeRejection);
}
/**
* Méthode permettant de créer une écriture de rejet de chèque (L'extourne de l'écriture de
* paiement)
*
* @param chequeRejection Un rejet de cheque brouillon
* @param company Une société
* @return L'écriture de rejet de chèque
* @throws AxelorException
*/
public Move createChequeRejectionMove(ChequeRejection chequeRejection, Company company)
throws AxelorException {
this.testCompanyField(company);
Journal journal = company.getAccountConfig().getRejectJournal();
PaymentVoucher paymentVoucher = chequeRejection.getPaymentVoucher();
Move paymentMove = paymentVoucher.getGeneratedMove();
Partner partner = paymentVoucher.getPartner();
InterbankCodeLine interbankCodeLine = chequeRejection.getInterbankCodeLine();
String description = chequeRejection.getDescription();
LocalDate rejectionDate = chequeRejection.getRejectionDate();
// Move
Move move =
moveService
.getMoveCreateService()
.createMove(
journal,
company,
null,
partner,
rejectionDate,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
int ref = 1;
for (MoveLine moveLine : paymentMove.getMoveLineList()) {
if (moveLine.getCredit().compareTo(BigDecimal.ZERO) > 0) {
// Debit MoveLine
MoveLine debitMoveLine =
moveLineService.createMoveLine(
move,
partner,
moveLine.getAccount(),
moveLine.getCredit(),
true,
rejectionDate,
ref,
chequeRejection.getName(),
chequeRejection.getDescription());
move.getMoveLineList().add(debitMoveLine);
debitMoveLine.setInterbankCodeLine(interbankCodeLine);
debitMoveLine.setDescription(description);
} else {
// Credit MoveLine
MoveLine creditMoveLine =
moveLineService.createMoveLine(
move,
partner,
moveLine.getAccount(),
moveLine.getDebit(),
false,
rejectionDate,
ref,
chequeRejection.getName(),
chequeRejection.getDescription());
move.getMoveLineList().add(creditMoveLine);
creditMoveLine.setInterbankCodeLine(interbankCodeLine);
creditMoveLine.setDescription(description);
}
ref++;
}
move.setRejectOk(true);
moveService.getMoveValidateService().validate(move);
return move;
}
/**
* Procédure permettant de vérifier les champs d'une société
*
* @param company Une société
* @throws AxelorException
*/
public void testCompanyField(Company company) throws AxelorException {
accountConfigService.getRejectJournal(accountConfigService.getAccountConfig(company));
}
/**
* Procédure permettant d'assigner une séquence de rejet de chèque
*
* @param chequeRejection Un rejet de chèque
* @throws AxelorException
*/
public void setSequence(ChequeRejection chequeRejection) throws AxelorException {
String seq =
sequenceService.getSequenceNumber(
SequenceRepository.CHEQUE_REJECT, chequeRejection.getCompany());
if (seq == null) {
throw new AxelorException(
chequeRejection,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.CHECK_REJECTION_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
chequeRejection.getCompany().getName());
}
chequeRejection.setName(seq);
}
}

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.account.service;
import com.axelor.apps.account.db.DepositSlip;
import com.axelor.exception.AxelorException;
import java.io.IOException;
public interface DepositSlipService {
/**
* Load payments into deposit slip.
*
* @param depositSlip
* @throws AxelorException
*/
void loadPayments(DepositSlip depositSlip) throws AxelorException;
/**
* Publish deposit slip.
*
* @param depositSlip
* @return
* @throws AxelorException
* @throws IOException
*/
String publish(DepositSlip depositSlip) throws AxelorException;
/**
* Get report filename.
*
* @param depositSlip
* @return
* @throws AxelorException
*/
String getFilename(DepositSlip depositSlip) throws AxelorException;
}

View File

@ -0,0 +1,177 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.service;
import com.axelor.apps.ReportFactory;
import com.axelor.apps.account.db.DepositSlip;
import com.axelor.apps.account.db.PaymentVoucher;
import com.axelor.apps.account.db.repo.PaymentModeRepository;
import com.axelor.apps.account.db.repo.PaymentVoucherRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.report.IReport;
import com.axelor.apps.account.service.payment.paymentvoucher.PaymentVoucherConfirmService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.tool.QueryBuilder;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.List;
public class DepositSlipServiceImpl implements DepositSlipService {
@Override
@Transactional(rollbackOn = {Exception.class})
public void loadPayments(DepositSlip depositSlip) throws AxelorException {
if (depositSlip.getPublicationDate() != null) {
throw new AxelorException(
depositSlip,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.DEPOSIT_SLIP_ALREADY_PUBLISHED));
}
depositSlip.clearPaymentVoucherList();
fetchPaymentVouchers(depositSlip).forEach(depositSlip::addPaymentVoucherListItem);
compute(depositSlip);
}
@Override
@Transactional(rollbackOn = {Exception.class})
public String publish(DepositSlip depositSlip) throws AxelorException {
confirmPayments(depositSlip);
ReportSettings settings =
ReportFactory.createReport(getReportName(depositSlip), getFilename(depositSlip));
settings.addParam("DepositSlipId", depositSlip.getId());
settings.addParam("Locale", ReportSettings.getPrintingLocale(null));
settings.addFormat("pdf");
String fileLink = settings.toAttach(depositSlip).generate().getFileLink();
depositSlip.setPublicationDate(Beans.get(AppBaseService.class).getTodayDate());
return fileLink;
}
@Override
public String getFilename(DepositSlip depositSlip) throws AxelorException {
String name;
switch (depositSlip.getPaymentModeTypeSelect()) {
case PaymentModeRepository.TYPE_CHEQUE:
name = I18n.get("Cheque deposit slip");
break;
case PaymentModeRepository.TYPE_CASH:
name = I18n.get("Cash deposit slip");
break;
default:
throw new AxelorException(
depositSlip,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
IExceptionMessage.DEPOSIT_SLIP_UNSUPPORTED_PAYMENT_MODE_TYPE);
}
return String.format("%s - %s", name, depositSlip.getDepositNumber());
}
private String getReportName(DepositSlip depositSlip) throws AxelorException {
switch (depositSlip.getPaymentModeTypeSelect()) {
case PaymentModeRepository.TYPE_CHEQUE:
return IReport.CHEQUE_DEPOSIT_SLIP;
case PaymentModeRepository.TYPE_CASH:
return IReport.CASH_DEPOSIT_SLIP;
default:
throw new AxelorException(
depositSlip,
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
IExceptionMessage.DEPOSIT_SLIP_UNSUPPORTED_PAYMENT_MODE_TYPE);
}
}
private void compute(DepositSlip depositSlip) {
if (depositSlip.getPaymentVoucherList() != null) {
List<PaymentVoucher> paymentVoucherList = depositSlip.getPaymentVoucherList();
BigDecimal totalAmount =
paymentVoucherList
.stream()
.map(PaymentVoucher::getPaidAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add);
depositSlip.setTotalAmount(totalAmount);
depositSlip.setChequeCount(paymentVoucherList.size());
}
}
private List<PaymentVoucher> fetchPaymentVouchers(DepositSlip depositSlip) {
QueryBuilder<PaymentVoucher> queryBuilder = QueryBuilder.of(PaymentVoucher.class);
if (depositSlip.getPaymentModeTypeSelect() != 0) {
queryBuilder.add("self.paymentMode.typeSelect = :paymentModeTypeSelect");
queryBuilder.bind("paymentModeTypeSelect", depositSlip.getPaymentModeTypeSelect());
}
if (depositSlip.getCompany() != null) {
queryBuilder.add("self.company = :company");
queryBuilder.bind("company", depositSlip.getCompany());
}
if (depositSlip.getCurrency() != null) {
queryBuilder.add("self.currency = :currency");
queryBuilder.bind("currency", depositSlip.getCurrency());
}
if (depositSlip.getCompanyBankDetails() != null
&& Beans.get(AppBaseService.class).getAppBase().getManageMultiBanks()) {
queryBuilder.add("self.companyBankDetails = :companyBankDetails");
queryBuilder.bind("companyBankDetails", depositSlip.getCompanyBankDetails());
}
if (depositSlip.getFromDate() != null) {
if (depositSlip.getToDate() != null) {
queryBuilder.add(
"self.chequeDate IS NULL OR self.chequeDate BETWEEN :fromDate AND :toDate");
queryBuilder.bind("fromDate", depositSlip.getFromDate());
queryBuilder.bind("toDate", depositSlip.getToDate());
} else {
queryBuilder.add("self.chequeDate IS NULL OR self.chequeDate >= :fromDate");
queryBuilder.bind("fromDate", depositSlip.getFromDate());
}
} else if (depositSlip.getToDate() != null) {
queryBuilder.add("self.chequeDate IS NULL OR self.chequeDate <= :toDate");
queryBuilder.bind("toDate", depositSlip.getToDate());
}
queryBuilder.add("self.depositSlip IS NULL");
queryBuilder.add("self.statusSelect = :statusSelect");
queryBuilder.bind("statusSelect", PaymentVoucherRepository.STATUS_WAITING_FOR_DEPOSIT_SLIP);
return queryBuilder.build().fetch();
}
private void confirmPayments(DepositSlip depositSlip) throws AxelorException {
if (depositSlip.getPaymentVoucherList() != null) {
PaymentVoucherConfirmService paymentVoucherConfirmService =
Beans.get(PaymentVoucherConfirmService.class);
for (PaymentVoucher paymentVoucher : depositSlip.getPaymentVoucherList()) {
paymentVoucherConfirmService.createMoveAndConfirm(paymentVoucher);
}
}
}
}

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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.FiscalPosition;
import com.axelor.apps.base.service.tax.FiscalPositionService;
public interface FiscalPositionAccountService extends FiscalPositionService {
/**
* Replace the account from the fiscal position account equiv list if match the given account
*
* @param fiscalPosition
* @param account
* @return
*/
public Account getAccount(FiscalPosition fiscalPosition, Account account);
}

View File

@ -0,0 +1,42 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountEquiv;
import com.axelor.apps.account.db.FiscalPosition;
import com.axelor.apps.base.service.tax.FiscalPositionServiceImpl;
public class FiscalPositionAccountServiceImpl extends FiscalPositionServiceImpl
implements FiscalPositionAccountService {
@Override
public Account getAccount(FiscalPosition fiscalPosition, Account account) {
if (fiscalPosition != null && fiscalPosition.getAccountEquivList() != null) {
for (AccountEquiv accountEquiv : fiscalPosition.getAccountEquivList()) {
if (accountEquiv.getFromAccount().equals(account) && accountEquiv.getToAccount() != null) {
return accountEquiv.getToAccount();
}
}
}
return account;
}
}

View File

@ -0,0 +1,28 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.FixedAssetLine;
import com.axelor.exception.AxelorException;
public interface FixedAssetLineService {
public void realize(FixedAssetLine fixedAssetLine) throws AxelorException;
public void generateDisposalMove(FixedAssetLine fixedAssetLine) throws AxelorException;
}

View File

@ -0,0 +1,249 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.FixedAsset;
import com.axelor.apps.account.db.FixedAssetLine;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.repo.FixedAssetLineRepository;
import com.axelor.apps.account.db.repo.FixedAssetRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.service.move.MoveCreateService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FixedAssetLineServiceImpl implements FixedAssetLineService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@Inject private FixedAssetLineRepository fixedAssetLineRepo;
@Inject private MoveCreateService moveCreateService;
@Inject private MoveRepository moveRepo;
@Override
@Transactional(rollbackOn = {Exception.class})
public void realize(FixedAssetLine fixedAssetLine) throws AxelorException {
generateMove(fixedAssetLine);
fixedAssetLine.setStatusSelect(FixedAssetLineRepository.STATUS_REALIZED);
FixedAsset fixedAsset = fixedAssetLine.getFixedAsset();
BigDecimal residualValue = fixedAsset.getResidualValue();
fixedAsset.setResidualValue(residualValue.subtract(fixedAssetLine.getDepreciation()));
FixedAssetLine plannedFixedAssetLine =
fixedAsset
.getFixedAssetLineList()
.stream()
.filter(line -> line.getStatusSelect() == FixedAssetLineRepository.STATUS_PLANNED)
.findAny()
.orElse(null);
if (plannedFixedAssetLine == null
&& fixedAsset.getDisposalValue().compareTo(BigDecimal.ZERO) == 0) {
fixedAsset.setStatusSelect(FixedAssetRepository.STATUS_DEPRECIATED);
}
fixedAssetLineRepo.save(fixedAssetLine);
}
@Transactional(rollbackOn = {Exception.class})
private void generateMove(FixedAssetLine fixedAssetLine) throws AxelorException {
FixedAsset fixedAsset = fixedAssetLine.getFixedAsset();
Journal journal = fixedAsset.getJournal();
Company company = fixedAsset.getCompany();
Partner partner = fixedAsset.getPartner();
LocalDate date = fixedAsset.getAcquisitionDate();
log.debug(
"Creating an fixed asset line specific accounting entry {} (Company : {}, Journal : {})",
new Object[] {fixedAsset.getReference(), company.getName(), journal.getCode()});
// Creating move
Move move =
moveCreateService.createMove(
journal,
company,
company.getCurrency(),
partner,
date,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
if (move != null) {
List<MoveLine> moveLines = new ArrayList<MoveLine>();
String origin = fixedAsset.getReference();
Account debitLineAccount = fixedAsset.getFixedAssetCategory().getChargeAccount();
Account creditLineAccount = fixedAsset.getFixedAssetCategory().getDepreciationAccount();
BigDecimal amount = fixedAssetLine.getDepreciation();
// Creating accounting debit move line
MoveLine debitMoveLine =
new MoveLine(
move,
partner,
debitLineAccount,
date,
null,
1,
amount,
BigDecimal.ZERO,
fixedAsset.getName(),
origin,
null,
BigDecimal.ZERO,
date);
moveLines.add(debitMoveLine);
// Creating accounting debit move line
MoveLine creditMoveLine =
new MoveLine(
move,
partner,
creditLineAccount,
date,
null,
2,
BigDecimal.ZERO,
amount,
fixedAsset.getName(),
origin,
null,
BigDecimal.ZERO,
date);
moveLines.add(creditMoveLine);
move.getMoveLineList().addAll(moveLines);
}
moveRepo.save(move);
fixedAssetLine.setDepreciationAccountMove(move);
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void generateDisposalMove(FixedAssetLine fixedAssetLine) throws AxelorException {
FixedAsset fixedAsset = fixedAssetLine.getFixedAsset();
Journal journal = fixedAsset.getJournal();
Company company = fixedAsset.getCompany();
Partner partner = fixedAsset.getPartner();
LocalDate date = fixedAsset.getAcquisitionDate();
// Creating move
Move move =
moveCreateService.createMove(
journal,
company,
company.getCurrency(),
partner,
date,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
if (move != null) {
List<MoveLine> moveLines = new ArrayList<MoveLine>();
String origin = fixedAsset.getReference();
Account chargeAccount = fixedAsset.getFixedAssetCategory().getChargeAccount();
Account depreciationAccount = fixedAsset.getFixedAssetCategory().getDepreciationAccount();
Account purchaseAccount = fixedAsset.getPurchaseAccount();
BigDecimal chargeAmount = fixedAssetLine.getResidualValue();
BigDecimal cumulativeDepreciationAmount = fixedAssetLine.getCumulativeDepreciation();
// Creating accounting debit move line for charge account
MoveLine chargeAccountDebitMoveLine =
new MoveLine(
move,
partner,
chargeAccount,
date,
null,
1,
chargeAmount,
BigDecimal.ZERO,
fixedAsset.getName(),
origin,
null,
BigDecimal.ZERO,
date);
moveLines.add(chargeAccountDebitMoveLine);
// Creating accounting debit move line for deprecation account
MoveLine deprecationAccountDebitMoveLine =
new MoveLine(
move,
partner,
depreciationAccount,
date,
null,
1,
cumulativeDepreciationAmount,
BigDecimal.ZERO,
fixedAsset.getName(),
origin,
null,
BigDecimal.ZERO,
date);
moveLines.add(deprecationAccountDebitMoveLine);
// Creating accounting credit move line
MoveLine creditMoveLine =
new MoveLine(
move,
partner,
purchaseAccount,
date,
null,
2,
BigDecimal.ZERO,
fixedAsset.getGrossValue(),
fixedAsset.getName(),
origin,
null,
BigDecimal.ZERO,
date);
moveLines.add(creditMoveLine);
move.getMoveLineList().addAll(moveLines);
}
moveRepo.save(move);
fixedAsset.setDisposalMove(move);
}
}

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.account.service;
import com.axelor.apps.account.db.FixedAsset;
import com.axelor.apps.account.db.Invoice;
import com.axelor.exception.AxelorException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
public interface FixedAssetService {
/**
* Allow to generate and compute the fixed asset lines
*
* @param fixedAsset
* @return
*/
public FixedAsset generateAndcomputeLines(FixedAsset fixedAsset);
/**
* Allow to create fixed asset from invoice
*
* @param invoice
* @return
* @throws AxelorException
*/
public List<FixedAsset> createFixedAssets(Invoice invoice) throws AxelorException;
/**
* Allow to disposal remaining depreciation
*
* @param disposalDate
* @param disposalAmount
* @param fixedAsset
* @throws AxelorException
*/
public void disposal(LocalDate disposalDate, BigDecimal disposalAmount, FixedAsset fixedAsset)
throws AxelorException;
}

View File

@ -0,0 +1,329 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.FixedAsset;
import com.axelor.apps.account.db.FixedAssetLine;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.repo.FixedAssetLineRepository;
import com.axelor.apps.account.db.repo.FixedAssetRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
public class FixedAssetServiceImpl implements FixedAssetService {
@Inject FixedAssetRepository fixedAssetRepo;
@Inject FixedAssetLineService fixedAssetLineService;
@Override
public FixedAsset generateAndcomputeLines(FixedAsset fixedAsset) {
BigDecimal depreciationValue = this.computeDepreciationValue(fixedAsset);
BigDecimal cumulativeValue = depreciationValue;
LocalDate depreciationDate = fixedAsset.getFirstDepreciationDate();
LocalDate acquisitionDate = fixedAsset.getAcquisitionDate();
int numberOfDepreciation = fixedAsset.getNumberOfDepreciation();
boolean isProrataTemporis = fixedAsset.getFixedAssetCategory().getIsProrataTemporis();
LocalDate endDate = depreciationDate.plusMonths(fixedAsset.getDurationInMonth());
int counter = 1;
int scale = Beans.get(AppBaseService.class).getNbDecimalDigitForUnitPrice();
numberOfDepreciation--;
while (depreciationDate.isBefore(endDate)) {
FixedAssetLine fixedAssetLine = new FixedAssetLine();
fixedAssetLine.setStatusSelect(FixedAssetLineRepository.STATUS_PLANNED);
fixedAssetLine.setDepreciationDate(depreciationDate);
fixedAssetLine.setDepreciation(depreciationValue);
fixedAssetLine.setCumulativeDepreciation(cumulativeValue);
fixedAssetLine.setResidualValue(
fixedAsset.getGrossValue().subtract(fixedAssetLine.getCumulativeDepreciation()));
fixedAsset.addFixedAssetLineListItem(fixedAssetLine);
if (counter == numberOfDepreciation) {
depreciationValue = fixedAssetLine.getResidualValue();
cumulativeValue = cumulativeValue.add(depreciationValue);
depreciationDate = depreciationDate.plusMonths(fixedAsset.getPeriodicityInMonth());
if (isProrataTemporis) {
endDate =
depreciationDate.minusDays(
ChronoUnit.DAYS.between(acquisitionDate, fixedAsset.getFirstDepreciationDate()));
depreciationDate = endDate.minusDays(1);
}
counter++;
continue;
}
if (fixedAsset.getComputationMethodSelect().equals("degressive")) {
if (counter > 2 && fixedAsset.getNumberOfDepreciation() > 3) {
if (counter == 3) {
int remainingYear = fixedAsset.getNumberOfDepreciation() - 3;
depreciationValue =
fixedAssetLine
.getResidualValue()
.divide(new BigDecimal(remainingYear), RoundingMode.HALF_EVEN);
}
} else {
depreciationValue =
this.computeDepreciation(fixedAsset, fixedAssetLine.getResidualValue(), false);
}
depreciationDate = depreciationDate.plusMonths(fixedAsset.getPeriodicityInMonth());
} else {
depreciationValue =
this.computeDepreciation(fixedAsset, fixedAsset.getResidualValue(), false);
depreciationDate = depreciationDate.plusMonths(fixedAsset.getPeriodicityInMonth());
}
depreciationValue = depreciationValue.setScale(scale, RoundingMode.HALF_EVEN);
cumulativeValue =
cumulativeValue.add(depreciationValue).setScale(scale, RoundingMode.HALF_EVEN);
counter++;
}
return fixedAsset;
}
private BigDecimal computeDepreciationValue(FixedAsset fixedAsset) {
BigDecimal depreciationValue = BigDecimal.ZERO;
depreciationValue = this.computeDepreciation(fixedAsset, fixedAsset.getGrossValue(), true);
return depreciationValue;
}
private BigDecimal computeProrataTemporis(FixedAsset fixedAsset, boolean isFirstYear) {
float prorataTemporis = 1;
if (isFirstYear && fixedAsset.getFixedAssetCategory().getIsProrataTemporis()) {
LocalDate acquisitionDate = fixedAsset.getAcquisitionDate();
LocalDate depreciationDate = fixedAsset.getFirstDepreciationDate();
long monthsBetweenDates =
ChronoUnit.MONTHS.between(
acquisitionDate.withDayOfMonth(1), depreciationDate.withDayOfMonth(1));
prorataTemporis = monthsBetweenDates / fixedAsset.getPeriodicityInMonth().floatValue();
}
return new BigDecimal(prorataTemporis);
}
private BigDecimal computeDepreciation(
FixedAsset fixedAsset, BigDecimal residualValue, boolean isFirstYear) {
int scale = Beans.get(AppBaseService.class).getNbDecimalDigitForUnitPrice();
int numberOfDepreciation =
fixedAsset.getFixedAssetCategory().getIsProrataTemporis()
? fixedAsset.getNumberOfDepreciation() - 1
: fixedAsset.getNumberOfDepreciation();
float depreciationRate = 1f / numberOfDepreciation * 100f;
BigDecimal ddRate = BigDecimal.ONE;
BigDecimal prorataTemporis = this.computeProrataTemporis(fixedAsset, isFirstYear);
if (fixedAsset.getComputationMethodSelect().equals("degressive")) {
ddRate = fixedAsset.getDegressiveCoef();
}
return residualValue
.multiply(new BigDecimal(depreciationRate))
.multiply(ddRate)
.multiply(prorataTemporis)
.divide(new BigDecimal(100), scale);
}
@Override
@Transactional(rollbackOn = {Exception.class})
public List<FixedAsset> createFixedAssets(Invoice invoice) throws AxelorException {
if (invoice == null || CollectionUtils.isEmpty(invoice.getInvoiceLineList())) {
return null;
}
AccountConfig accountConfig =
Beans.get(AccountConfigService.class).getAccountConfig(invoice.getCompany());
List<FixedAsset> fixedAssetList = new ArrayList<FixedAsset>();
for (InvoiceLine invoiceLine : invoice.getInvoiceLineList()) {
if (accountConfig.getFixedAssetCatReqOnInvoice()
&& invoiceLine.getFixedAssets()
&& invoiceLine.getFixedAssetCategory() == null) {
throw new AxelorException(
invoiceLine,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.INVOICE_LINE_ERROR_FIXED_ASSET_CATEGORY),
invoiceLine.getProductName());
}
if (!invoiceLine.getFixedAssets() || invoiceLine.getFixedAssetCategory() == null) {
continue;
}
FixedAsset fixedAsset = new FixedAsset();
fixedAsset.setFixedAssetCategory(invoiceLine.getFixedAssetCategory());
if (fixedAsset.getFixedAssetCategory().getIsValidateFixedAsset()) {
fixedAsset.setStatusSelect(FixedAssetRepository.STATUS_VALIDATED);
} else {
fixedAsset.setStatusSelect(FixedAssetRepository.STATUS_DRAFT);
}
fixedAsset.setAcquisitionDate(invoice.getInvoiceDate());
fixedAsset.setFirstDepreciationDate(invoice.getInvoiceDate());
fixedAsset.setReference(invoice.getInvoiceId());
fixedAsset.setName(invoiceLine.getProductName() + " (" + invoiceLine.getQty() + ")");
fixedAsset.setCompany(fixedAsset.getFixedAssetCategory().getCompany());
fixedAsset.setJournal(fixedAsset.getFixedAssetCategory().getJournal());
fixedAsset.setComputationMethodSelect(
fixedAsset.getFixedAssetCategory().getComputationMethodSelect());
fixedAsset.setDegressiveCoef(fixedAsset.getFixedAssetCategory().getDegressiveCoef());
fixedAsset.setNumberOfDepreciation(
fixedAsset.getFixedAssetCategory().getNumberOfDepreciation());
fixedAsset.setPeriodicityInMonth(fixedAsset.getFixedAssetCategory().getPeriodicityInMonth());
fixedAsset.setDurationInMonth(fixedAsset.getFixedAssetCategory().getDurationInMonth());
fixedAsset.setGrossValue(invoiceLine.getCompanyExTaxTotal());
fixedAsset.setPartner(invoice.getPartner());
fixedAsset.setPurchaseAccount(invoiceLine.getAccount());
fixedAsset.setInvoiceLine(invoiceLine);
this.generateAndcomputeLines(fixedAsset);
fixedAssetList.add(fixedAssetRepo.save(fixedAsset));
}
return fixedAssetList;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void disposal(LocalDate disposalDate, BigDecimal disposalAmount, FixedAsset fixedAsset)
throws AxelorException {
Map<Integer, List<FixedAssetLine>> FixedAssetLineMap =
fixedAsset
.getFixedAssetLineList()
.stream()
.collect(Collectors.groupingBy(fa -> fa.getStatusSelect()));
List<FixedAssetLine> previousPlannedLineList =
FixedAssetLineMap.get(FixedAssetLineRepository.STATUS_PLANNED);
List<FixedAssetLine> previousRealizedLineList =
FixedAssetLineMap.get(FixedAssetLineRepository.STATUS_REALIZED);
FixedAssetLine previousPlannedLine =
previousPlannedLineList != null && !previousPlannedLineList.isEmpty()
? previousPlannedLineList.get(0)
: null;
FixedAssetLine previousRealizedLine =
previousRealizedLineList != null && !previousRealizedLineList.isEmpty()
? previousRealizedLineList.get(previousRealizedLineList.size() - 1)
: null;
if (previousPlannedLine != null
&& disposalDate.isAfter(previousPlannedLine.getDepreciationDate())) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.FIXED_ASSET_DISPOSAL_DATE_ERROR_2));
}
if (previousRealizedLine != null
&& disposalDate.isBefore(previousRealizedLine.getDepreciationDate())) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.FIXED_ASSET_DISPOSAL_DATE_ERROR_1));
}
if (disposalAmount.compareTo(BigDecimal.ZERO) != 0) {
FixedAssetLine depreciationFixedAssetLine =
generateProrataDepreciationLine(fixedAsset, disposalDate, previousRealizedLine);
fixedAssetLineService.realize(depreciationFixedAssetLine);
fixedAssetLineService.generateDisposalMove(depreciationFixedAssetLine);
} else {
if (disposalAmount.compareTo(fixedAsset.getResidualValue()) != 0) {
return;
}
}
List<FixedAssetLine> fixedAssetLineList =
fixedAsset
.getFixedAssetLineList()
.stream()
.filter(
fixedAssetLine ->
fixedAssetLine.getStatusSelect() == FixedAssetLineRepository.STATUS_PLANNED)
.collect(Collectors.toList());
for (FixedAssetLine fixedAssetLine : fixedAssetLineList) {
fixedAsset.removeFixedAssetLineListItem(fixedAssetLine);
}
fixedAsset.setStatusSelect(FixedAssetRepository.STATUS_TRANSFERRED);
fixedAsset.setDisposalDate(disposalDate);
fixedAsset.setDisposalValue(disposalAmount);
fixedAssetRepo.save(fixedAsset);
}
private FixedAssetLine generateProrataDepreciationLine(
FixedAsset fixedAsset, LocalDate disposalDate, FixedAssetLine previousRealizedLine) {
LocalDate previousRealizedDate =
previousRealizedLine != null
? previousRealizedLine.getDepreciationDate()
: fixedAsset.getFirstDepreciationDate();
long monthsBetweenDates =
ChronoUnit.MONTHS.between(
previousRealizedDate.withDayOfMonth(1), disposalDate.withDayOfMonth(1));
FixedAssetLine fixedAssetLine = new FixedAssetLine();
fixedAssetLine.setDepreciationDate(disposalDate);
BigDecimal prorataTemporis =
new BigDecimal(monthsBetweenDates / fixedAsset.getPeriodicityInMonth().floatValue());
int scale = Beans.get(AppBaseService.class).getNbDecimalDigitForUnitPrice();
int numberOfDepreciation =
fixedAsset.getFixedAssetCategory().getIsProrataTemporis()
? fixedAsset.getNumberOfDepreciation() - 1
: fixedAsset.getNumberOfDepreciation();
float depreciationRate = 1f / numberOfDepreciation * 100f;
BigDecimal ddRate = BigDecimal.ONE;
if (fixedAsset.getComputationMethodSelect().equals("degressive")) {
ddRate = fixedAsset.getDegressiveCoef();
}
BigDecimal deprecationValue =
fixedAsset
.getGrossValue()
.multiply(new BigDecimal(depreciationRate))
.multiply(ddRate)
.multiply(prorataTemporis)
.divide(new BigDecimal(100), scale);
fixedAssetLine.setDepreciation(deprecationValue);
BigDecimal cumulativeValue =
previousRealizedLine != null
? previousRealizedLine.getCumulativeDepreciation().add(deprecationValue)
: deprecationValue;
fixedAssetLine.setCumulativeDepreciation(cumulativeValue);
fixedAssetLine.setResidualValue(
fixedAsset.getGrossValue().subtract(fixedAssetLine.getCumulativeDepreciation()));
fixedAsset.addFixedAssetLineListItem(fixedAssetLine);
return fixedAssetLine;
}
}

View File

@ -0,0 +1,112 @@
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoiceLine;
import com.axelor.apps.account.db.InvoiceTemplate;
import com.axelor.apps.account.db.InvoiceTemplateLine;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.service.invoice.generator.InvoiceGenerator;
import com.axelor.apps.account.service.invoice.generator.InvoiceLineGenerator;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.Product;
import com.axelor.exception.AxelorException;
import com.axelor.inject.Beans;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
public class InvoiceTemplateService {
@Transactional
public Invoice generateInvoiceFromTemplate(InvoiceTemplate invoiceTemplate)
throws AxelorException {
Partner partner = invoiceTemplate.getPartner();
Company company = invoiceTemplate.getCompany();
InvoiceGenerator invoiceGenerator =
new InvoiceGenerator(
InvoiceRepository.OPERATION_TYPE_SUPPLIER_PURCHASE,
company,
null,
null,
null,
partner,
partner,
partner.getCurrency(),
null,
"",
"",
null,
company.getDefaultBankDetails(),
null) {
@Override
public Invoice generate() throws AxelorException {
return super.createInvoiceHeader();
}
};
List<InvoiceLine> invoiceLineList = new ArrayList<>();
Invoice invoice = invoiceGenerator.generate();
int priority = 0;
for (InvoiceTemplateLine invoiceTemplateLine : invoiceTemplate.getMoveTemplateLineList()) {
invoiceLineList.addAll(createInvoiceLine(invoice, invoiceTemplateLine, priority));
priority++;
}
invoiceGenerator.populate(invoice, invoiceLineList);
Invoice returnInvoiced = Beans.get(InvoiceRepository.class).save(invoice);
return returnInvoiced;
}
protected List<InvoiceLine> createInvoiceLine(
Invoice invoice, InvoiceTemplateLine invoiceTemplateLine, int priority)
throws AxelorException {
Product product = invoiceTemplateLine.getProduct();
InvoiceLineGenerator invoiceLineGenerator =
new InvoiceLineGenerator(
invoice,
product,
invoiceTemplateLine.getProduct().getName(),
BigDecimal.ZERO,
BigDecimal.ZERO,
BigDecimal.ZERO,
"",
invoiceTemplateLine.getQty(),
invoiceTemplateLine.getProduct().getUnit(),
null,
priority,
BigDecimal.ZERO,
0,
BigDecimal.ZERO,
BigDecimal.ZERO,
false,
false,
null) {
@Override
public List<InvoiceLine> creates() throws AxelorException {
InvoiceLine invoiceLine = this.createInvoiceLine();
invoiceLine.setQty(BigDecimal.ONE);
invoiceLine.setPrice(BigDecimal.ZERO);
invoiceLine.setPriceDiscounted(BigDecimal.ZERO);
List<InvoiceLine> invoiceLines = new ArrayList<InvoiceLine>();
invoiceLines.add(invoiceLine);
return invoiceLines;
}
};
return invoiceLineGenerator.creates();
}
}

View File

@ -0,0 +1,72 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.Journal;
import com.axelor.db.JPA;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import javax.persistence.Query;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class JournalService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
/** Debit balance = debit - credit */
public static final Integer BALANCE_TYPE_DEBIT_BALANCE = 1;
/** Credit balance = credit - debit */
public static final Integer BALANCE_TYPE_CREDIT_BALANCE = 1;
/**
* Compute the balance of the journal, depending of the account type and balance type
*
* @param journal Journal
* @param accountType Technical type select of AccountType
* @param balanceType
* <p>1 : debit balance = debit - credit
* <p>2 : credit balance = credit - debit
* @return The balance (debit balance or credit balance)
*/
public BigDecimal computeBalance(Journal journal, int accountType, int balanceType) {
Query balanceQuery =
JPA.em()
.createQuery(
"select sum(self.debit - self.credit) from MoveLine self where self.move.journal = :journal "
+ "and self.move.ignoreInAccountingOk IN ('false', null) and self.move.statusSelect IN (2, 3) and self.account.accountType.technicalTypeSelect = :accountType");
balanceQuery.setParameter("journal", journal);
balanceQuery.setParameter("accountType", accountType);
BigDecimal balance = (BigDecimal) balanceQuery.getSingleResult();
if (balance != null) {
if (balanceType == BALANCE_TYPE_CREDIT_BALANCE) {
balance = balance.negate();
}
log.debug("Account balance : {}", balance);
return balance;
} else {
return BigDecimal.ZERO;
}
}
}

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.account.service;
import com.axelor.apps.account.db.AccountingReport;
import com.axelor.apps.base.db.Company;
import com.axelor.exception.AxelorException;
import com.axelor.meta.db.MetaFile;
import java.io.IOException;
import java.time.LocalDate;
public interface MoveLineExportService {
public MetaFile exportMoveLine(AccountingReport accountingReport)
throws AxelorException, IOException;
public void replayExportMoveLine(AccountingReport accountingReport)
throws AxelorException, IOException;
public AccountingReport createAccountingReport(
Company company, int exportTypeSelect, LocalDate startDate, LocalDate endDate)
throws AxelorException;
public void exportMoveLineTypeSelect1006(AccountingReport mlr, boolean replay)
throws AxelorException, IOException;
public void exportMoveLineTypeSelect1007(AccountingReport accountingReport, boolean replay)
throws AxelorException, IOException;
public void exportMoveLineTypeSelect1008(AccountingReport accountingReport, boolean replay)
throws AxelorException, IOException;
public void exportMoveLineTypeSelect1009(AccountingReport accountingReport, boolean replay)
throws AxelorException, IOException;
/**
* Export general balance to CSV file.
*
* @param accountingReport
* @return
* @throws AxelorException
* @throws IOException
*/
void exportMoveLineTypeSelect1010(AccountingReport accountingReport)
throws AxelorException, IOException;
}

View File

@ -0,0 +1,28 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.Notification;
import com.axelor.exception.AxelorException;
public interface NotificationService {
void populateNotificationItemList(Notification notification);
void validate(Notification notification) throws AxelorException;
}

View File

@ -0,0 +1,262 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Notification;
import com.axelor.apps.account.db.NotificationItem;
import com.axelor.apps.account.db.SubrogationRelease;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.NotificationRepository;
import com.axelor.apps.account.db.repo.SubrogationReleaseRepository;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.base.db.Company;
import com.axelor.db.JPA;
import com.axelor.exception.AxelorException;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;
import javax.persistence.TypedQuery;
public class NotificationServiceImpl implements NotificationService {
protected MoveService moveService;
protected ReconcileService reconcileService;
protected AccountConfigService accountConfigService;
protected SubrogationReleaseService subrogationReleaseService;
protected MoveRepository moveRepository;
@Inject
public NotificationServiceImpl(
MoveService moveService,
ReconcileService reconcileService,
AccountConfigService accountConfigService,
SubrogationReleaseService subrogationReleaseService,
MoveRepository moveRepository) {
this.moveService = moveService;
this.reconcileService = reconcileService;
this.accountConfigService = accountConfigService;
this.subrogationReleaseService = subrogationReleaseService;
this.moveRepository = moveRepository;
}
@Override
public void populateNotificationItemList(Notification notification) {
notification.clearNotificationItemList();
Comparator<Invoice> byInvoiceDate =
(i1, i2) -> i1.getInvoiceDate().compareTo(i2.getInvoiceDate());
Comparator<Invoice> byDueDate = (i1, i2) -> i1.getDueDate().compareTo(i2.getDueDate());
Comparator<Invoice> byInvoiceId = (i1, i2) -> i1.getInvoiceId().compareTo(i2.getInvoiceId());
List<Invoice> invoiceList = new ArrayList<Invoice>();
if (notification.getSubrogationRelease() != null) {
invoiceList =
notification
.getSubrogationRelease()
.getInvoiceSet()
.stream()
.sorted(byInvoiceDate.thenComparing(byDueDate).thenComparing(byInvoiceId))
.collect(Collectors.toList());
}
for (Invoice invoice : invoiceList) {
if (invoice.getAmountRemaining().signum() > 0) {
notification.addNotificationItemListItem(createNotificationItem(invoice));
}
}
}
protected NotificationItem createNotificationItem(Invoice invoice) {
return new NotificationItem(invoice, invoice.getAmountRemaining());
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void validate(Notification notification) throws AxelorException {
for (NotificationItem notificationItem : notification.getNotificationItemList()) {
this.createPaymentMove(notificationItem);
}
notification.setStatusSelect(NotificationRepository.STATUS_VALIDATED);
}
protected Journal getJournal(AccountConfig accountConfig) throws AxelorException {
return accountConfigService.getAutoMiscOpeJournal(accountConfig);
}
protected Account getAccount(AccountConfig accountConfig, NotificationItem notificationItem) {
Account account = accountConfig.getFactorCreditAccount();
if (notificationItem.getTypeSelect()
== NotificationRepository.TYPE_PAYMENT_TO_THE_FACTORE_AFTER_FACTORE_RETURN) {
account = accountConfig.getFactorDebitAccount();
}
return account;
}
@Transactional(rollbackOn = {Exception.class})
protected Move createPaymentMove(NotificationItem notificationItem) throws AxelorException {
Notification notification = notificationItem.getNotification();
Invoice invoice = notificationItem.getInvoice();
Company company = invoice.getCompany();
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
Journal journal = getJournal(accountConfig);
SubrogationRelease subrogationRelease = getSubrogationRelease(notificationItem);
String origin = computeOrigin(subrogationRelease, invoice);
BigDecimal amountPaid = notificationItem.getAmountPaid();
if (amountPaid.compareTo(BigDecimal.ZERO) == 0) {
return null;
}
Move paymentMove =
moveService
.getMoveCreateService()
.createMove(
journal,
company,
company.getCurrency(),
invoice.getPartner(),
notification.getPaymentDate(),
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
MoveLine creditMoveLine, debitMoveLine;
Account account = getAccount(accountConfig, notificationItem);
debitMoveLine =
moveService
.getMoveLineService()
.createMoveLine(
paymentMove,
invoice.getPartner(),
account,
amountPaid,
true,
notification.getPaymentDate(),
null,
1,
origin,
invoice.getInvoiceId());
creditMoveLine =
moveService
.getMoveLineService()
.createMoveLine(
paymentMove,
invoice.getPartner(),
invoice.getPartnerAccount(),
amountPaid,
false,
notification.getPaymentDate(),
null,
2,
origin,
invoice.getInvoiceId());
paymentMove.addMoveLineListItem(debitMoveLine);
paymentMove.addMoveLineListItem(creditMoveLine);
paymentMove = moveRepository.save(paymentMove);
moveService.getMoveValidateService().validate(paymentMove);
MoveLine invoiceMoveLine = findInvoiceAccountMoveLine(invoice);
MoveLine subrogationReleaseMoveLine = findSubrogationReleaseAccountMoveLine(invoice);
if (invoiceMoveLine.getAmountRemaining().compareTo(BigDecimal.ZERO) == 1) {
reconcileService.reconcile(invoiceMoveLine, creditMoveLine, true, true);
if (subrogationReleaseMoveLine != null
&& notificationItem.getTypeSelect()
== NotificationRepository.TYPE_PAYMENT_TO_THE_FACTORE) {
reconcileService.reconcile(debitMoveLine, subrogationReleaseMoveLine, true, false);
}
}
notificationItem.setMove(paymentMove);
if (subrogationRelease != null) {
subrogationReleaseService.clear(subrogationRelease);
}
return paymentMove;
}
protected String computeOrigin(SubrogationRelease subrogationRelease, Invoice invoice) {
return subrogationRelease != null
? subrogationRelease.getSequenceNumber()
: I18n.get("Payment notification") + " " + invoice.getInvoiceId();
}
protected SubrogationRelease getSubrogationRelease(NotificationItem notificationItem) {
Invoice invoice = notificationItem.getInvoice();
TypedQuery<SubrogationRelease> query =
JPA.em()
.createQuery(
"SELECT self FROM SubrogationRelease self JOIN self.invoiceSet invoices WHERE self.statusSelect = :statusSelect AND invoices.id IN (:invoiceId)",
SubrogationRelease.class);
query.setParameter("statusSelect", SubrogationReleaseRepository.STATUS_ACCOUNTED);
query.setParameter("invoiceId", invoice.getId());
List<SubrogationRelease> subrogationReleaseResultList = query.getResultList();
if (subrogationReleaseResultList != null && !subrogationReleaseResultList.isEmpty()) {
return subrogationReleaseResultList.get(0);
}
return null;
}
protected MoveLine findInvoiceAccountMoveLine(Invoice invoice) {
for (MoveLine moveLine : invoice.getMove().getMoveLineList()) {
if (moveLine.getAccount().equals(invoice.getPartnerAccount())) {
return moveLine;
}
}
throw new NoSuchElementException();
}
protected MoveLine findSubrogationReleaseAccountMoveLine(Invoice invoice) throws AxelorException {
if (invoice.getSubrogationReleaseMove() != null) {
for (MoveLine moveLine : invoice.getSubrogationReleaseMove().getMoveLineList()) {
if (moveLine.getCredit().compareTo(BigDecimal.ZERO) == 1) {
return moveLine;
}
}
}
return null;
}
}

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.account.service;
import com.axelor.apps.account.db.FiscalPosition;
import com.axelor.apps.base.db.Partner;
public class PartnerAccountService {
public String getDefaultSpecificTaxNote(Partner partner) {
FiscalPosition fiscalPosition = partner.getFiscalPosition();
if (fiscalPosition == null || !fiscalPosition.getCustomerSpecificNote()) {
return "";
}
return fiscalPosition.getCustomerSpecificNoteText();
}
}

View File

@ -0,0 +1,54 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.PaymentMode;
import com.axelor.apps.account.db.PaymentSchedule;
import com.axelor.apps.account.db.PaymentScheduleLine;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.exception.AxelorException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
public interface PaymentScheduleLineService {
PaymentScheduleLine createPaymentScheduleLine(
PaymentSchedule paymentSchedule,
BigDecimal inTaxAmount,
int scheduleLineSeq,
LocalDate scheduleDate);
List<PaymentScheduleLine> createPaymentScheduleLines(PaymentSchedule paymentSchedule);
/**
* Create a payment move for a payment schedule line with the given company bank details.
*
* @param paymentScheduleLine
* @param companyBankDetails
* @param paymentMode
* @return
* @throws AxelorException
*/
Move createPaymentMove(
PaymentScheduleLine paymentScheduleLine,
BankDetails companyBankDetails,
PaymentMode paymentMode)
throws AxelorException;
}

View File

@ -0,0 +1,362 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.DirectDebitManagement;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.PaymentMode;
import com.axelor.apps.account.db.PaymentSchedule;
import com.axelor.apps.account.db.PaymentScheduleLine;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.PaymentScheduleLineRepository;
import com.axelor.apps.account.db.repo.PaymentScheduleRepository;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.account.service.move.MoveToolService;
import com.axelor.apps.account.service.payment.PaymentModeService;
import com.axelor.apps.account.service.payment.PaymentService;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.AxelorException;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PaymentScheduleLineServiceImpl implements PaymentScheduleLineService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected AppBaseService appBaseService;
protected PaymentScheduleService paymentScheduleService;
protected MoveService moveService;
protected PaymentModeService paymentModeService;
protected SequenceService sequenceService;
protected AccountingSituationService accountingSituationService;
protected MoveToolService moveToolService;
protected PaymentService paymentService;
protected MoveLineRepository moveLineRepo;
protected PaymentScheduleLineRepository paymentScheduleLineRepo;
@Inject
public PaymentScheduleLineServiceImpl(
AppBaseService appBaseService,
PaymentScheduleService paymentScheduleService,
MoveService moveService,
PaymentModeService paymentModeService,
SequenceService sequenceService,
AccountingSituationService accountingSituationService,
MoveToolService moveToolService,
PaymentService paymentService,
MoveLineRepository moveLineRepo,
PaymentScheduleLineRepository paymentScheduleLineRepo) {
this.appBaseService = appBaseService;
this.paymentScheduleService = paymentScheduleService;
this.moveService = moveService;
this.paymentModeService = paymentModeService;
this.sequenceService = sequenceService;
this.accountingSituationService = accountingSituationService;
this.moveToolService = moveToolService;
this.paymentService = paymentService;
this.moveLineRepo = moveLineRepo;
this.paymentScheduleLineRepo = paymentScheduleLineRepo;
}
/**
* Création d'une ligne d'échéancier
*
* @param paymentSchedule L'échéancié attaché.
* @param invoiceTerm La facture d'échéance.
* @param scheduleLineSeq Le numéro d'échéance.
* @param scheduleDate La date d'échéance.
* @return
*/
@Override
public PaymentScheduleLine createPaymentScheduleLine(
PaymentSchedule paymentSchedule,
BigDecimal inTaxAmount,
int scheduleLineSeq,
LocalDate scheduleDate) {
PaymentScheduleLine paymentScheduleLine = new PaymentScheduleLine();
paymentScheduleLine.setScheduleLineSeq(scheduleLineSeq);
paymentScheduleLine.setScheduleDate(scheduleDate);
paymentScheduleLine.setInTaxAmount(inTaxAmount);
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_DRAFT);
if (paymentSchedule != null) {
paymentSchedule.addPaymentScheduleLineListItem(paymentScheduleLine);
}
log.debug(
"Création de la ligne de l'échéancier numéro {} pour la date du {} et la somme de {}",
new Object[] {
paymentScheduleLine.getScheduleLineSeq(),
paymentScheduleLine.getScheduleDate(),
paymentScheduleLine.getInTaxAmount()
});
return paymentScheduleLine;
}
/**
* En fonction des infos d'entête d'un échéancier, crée les lignes d'échéances
*
* @param paymentSchedule
*/
@Override
public List<PaymentScheduleLine> createPaymentScheduleLines(PaymentSchedule paymentSchedule) {
List<PaymentScheduleLine> paymentScheduleLines = new ArrayList<PaymentScheduleLine>();
int nbrTerm = paymentSchedule.getNbrTerm();
BigDecimal inTaxAmount = paymentSchedule.getInTaxAmount();
log.debug(
"Création de lignes pour l'échéancier numéro {} (nombre d'échéance : {}, montant : {})",
new Object[] {paymentSchedule.getPaymentScheduleSeq(), nbrTerm, inTaxAmount});
if (nbrTerm > 0 && inTaxAmount.compareTo(BigDecimal.ZERO) == 1) {
BigDecimal termAmount =
inTaxAmount.divide(new BigDecimal(nbrTerm), 2, RoundingMode.HALF_EVEN);
BigDecimal cumul = BigDecimal.ZERO;
for (int i = 1; i < nbrTerm + 1; i++) {
if (i == nbrTerm) {
termAmount = inTaxAmount.subtract(cumul);
} else {
cumul = cumul.add(termAmount);
}
paymentScheduleLines.add(
this.createPaymentScheduleLine(
paymentSchedule, termAmount, i, paymentSchedule.getStartDate().plusMonths(i - 1)));
}
}
return paymentScheduleLines;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public Move createPaymentMove(
PaymentScheduleLine paymentScheduleLine,
BankDetails companyBankDetails,
PaymentMode paymentMode)
throws AxelorException {
Preconditions.checkNotNull(paymentScheduleLine);
Preconditions.checkNotNull(companyBankDetails);
PaymentSchedule paymentSchedule = paymentScheduleLine.getPaymentSchedule();
Company company = paymentSchedule.getCompany();
Partner partner = paymentSchedule.getPartner();
Journal journal =
paymentModeService.getPaymentModeJournal(paymentMode, company, companyBankDetails);
BigDecimal amount = paymentScheduleLine.getInTaxAmount();
String name = paymentScheduleLine.getName();
LocalDate todayDate = appBaseService.getTodayDate();
Account account = accountingSituationService.getCustomerAccount(partner, company);
Move move =
moveService
.getMoveCreateService()
.createMove(
journal,
company,
null,
partner,
paymentMode,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
MoveLine creditMoveLine =
moveService
.getMoveLineService()
.createMoveLine(move, partner, account, amount, false, todayDate, 1, name, null);
move.addMoveLineListItem(creditMoveLine);
creditMoveLine = moveLineRepo.save(creditMoveLine);
Account paymentModeAccount =
paymentModeService.getPaymentModeAccount(paymentMode, company, companyBankDetails);
MoveLine debitMoveLine =
moveService
.getMoveLineService()
.createMoveLine(
move, partner, paymentModeAccount, amount, true, todayDate, 2, name, null);
move.addMoveLineListItem(debitMoveLine);
debitMoveLine = moveLineRepo.save(debitMoveLine);
moveService.getMoveValidateService().validate(move);
// Reconcile
if (paymentSchedule.getTypeSelect() == PaymentScheduleRepository.TYPE_TERMS
&& paymentSchedule.getInvoiceSet() != null) {
List<MoveLine> debitMoveLineList =
paymentSchedule
.getInvoiceSet()
.stream()
.sorted(Comparator.comparing(Invoice::getDueDate))
.map(invoice -> moveService.getMoveLineService().getDebitCustomerMoveLine(invoice))
.collect(Collectors.toList());
if (moveToolService.isSameAccount(debitMoveLineList, account)) {
List<MoveLine> creditMoveLineList = Lists.newArrayList(creditMoveLine);
paymentService.useExcessPaymentOnMoveLines(debitMoveLineList, creditMoveLineList);
}
}
paymentScheduleLine.setDirectDebitAmount(amount);
paymentScheduleLine.setInTaxAmountPaid(amount);
paymentScheduleLine.setAdvanceOrPaymentMove(move);
paymentScheduleLine.setAdvanceMoveLine(creditMoveLine);
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_VALIDATED);
paymentScheduleService.closePaymentScheduleIfAllPaid(paymentSchedule);
return move;
}
/**
* Procédure permettant d'assigner un numéro de prélèvement à l'échéance à prélever Si plusieurs
* échéance d'un même échéancier sont à prélever, alors on utilise un objet de gestion de
* prélèvement encadrant l'ensemble des échéances en question Sinon on assigne simplement un
* numéro de prélèvement à l'échéance
*
* @param paymentScheduleLineList Une liste d'échéance à prélever
* @param paymentScheduleLine L'échéance traité
* @param company Une société
* @param paymentMode TODO
* @param journal Un journal (prélèvement mensu masse ou grand compte)
* @throws AxelorException
*/
protected void setDebitNumber(
List<PaymentScheduleLine> paymentScheduleLineList,
PaymentScheduleLine paymentScheduleLine,
Company company,
PaymentMode paymentMode)
throws AxelorException {
if (hasOtherPaymentScheduleLine(paymentScheduleLineList, paymentScheduleLine)) {
DirectDebitManagement directDebitManagement =
getDirectDebitManagement(paymentScheduleLineList, paymentScheduleLine);
if (directDebitManagement == null) {
directDebitManagement =
createDirectDebitManagement(getDirectDebitSequence(company, paymentMode), company);
}
paymentScheduleLine.setDirectDebitManagement(directDebitManagement);
directDebitManagement.getPaymentScheduleLineList().add(paymentScheduleLine);
} else {
paymentScheduleLine.setDebitNumber(getDirectDebitSequence(company, paymentMode));
}
}
protected void setDebitNumber(PaymentScheduleLine paymentScheduleLine, PaymentMode paymentMode)
throws AxelorException {
PaymentSchedule paymentSchedule = paymentScheduleLine.getPaymentSchedule();
List<PaymentScheduleLine> paymentScheduleLineList =
paymentSchedule.getPaymentScheduleLineList();
Company company = paymentSchedule.getCompany();
setDebitNumber(paymentScheduleLineList, paymentScheduleLine, company, paymentMode);
}
/**
* Y a-t-il d'autres échéance a exporter pour le même payeur ?
*
* @param pslList : une liste d'échéance
* @param psl
* @return
*/
protected boolean hasOtherPaymentScheduleLine(
List<PaymentScheduleLine> pslList, PaymentScheduleLine psl) {
int i = 0;
for (PaymentScheduleLine paymentScheduleLine : pslList) {
paymentScheduleLine = paymentScheduleLineRepo.find(paymentScheduleLine.getId());
if (psl.getPaymentSchedule().equals(paymentScheduleLine.getPaymentSchedule())) {
i++;
}
}
return i > 1;
}
/**
* Procédure permettant de récupérer l'objet de gestion déjà créé lors du prélèvement d'une autre
* échéance
*
* @param pslList La liste d'échéance à prélever
* @param psl L'échéance à prélever
* @return L'objet de gestion trouvé
*/
protected DirectDebitManagement getDirectDebitManagement(
List<PaymentScheduleLine> pslList, PaymentScheduleLine psl) {
for (PaymentScheduleLine paymentScheduleLine : pslList) {
paymentScheduleLine = paymentScheduleLineRepo.find(paymentScheduleLine.getId());
if (psl.getPaymentSchedule().equals(paymentScheduleLine.getPaymentSchedule())) {
if (paymentScheduleLine.getDirectDebitManagement() != null) {
return paymentScheduleLine.getDirectDebitManagement();
}
}
}
return null;
}
/**
* Procédure permettant de créer un objet de gestion de prélèvement
*
* @param sequence La séquence de prélèvement à utiliser
* @param company Une société
* @return
*/
protected DirectDebitManagement createDirectDebitManagement(String sequence, Company company) {
DirectDebitManagement directDebitManagement = new DirectDebitManagement();
directDebitManagement.setDebitNumber(sequence);
directDebitManagement.setInvoiceSet(new HashSet<Invoice>());
directDebitManagement.setPaymentScheduleLineList(new ArrayList<PaymentScheduleLine>());
directDebitManagement.setCompany(company);
return directDebitManagement;
}
protected String getDirectDebitSequence(Company company, PaymentMode paymentMode)
throws AxelorException {
// TODO manage multi bank
return sequenceService.getSequenceNumber(
paymentModeService.getPaymentModeSequence(paymentMode, company, null));
}
}

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.account.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.PaymentMode;
import com.axelor.apps.account.db.PaymentSchedule;
import com.axelor.apps.account.db.PaymentScheduleLine;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
public interface PaymentScheduleService {
PaymentSchedule createPaymentSchedule(
Partner partner, Company company, Set<Invoice> invoices, LocalDate startDate, int nbrTerm)
throws AxelorException;
PaymentSchedule createPaymentSchedule(
Partner partner,
Invoice invoice,
Company company,
LocalDate date,
LocalDate startDate,
int nbrTerm,
BankDetails bankDetails,
PaymentMode paymentMode)
throws AxelorException;
String getPaymentScheduleSequence(Company company) throws AxelorException;
BigDecimal getInvoiceTermTotal(PaymentSchedule paymentSchedule);
void updatePaymentSchedule(PaymentSchedule paymentSchedule, BigDecimal inTaxTotal);
PaymentSchedule createPaymentSchedule(
Partner partner,
Company company,
LocalDate date,
LocalDate firstTermDate,
BigDecimal initialInTaxAmount,
int nbrTerm,
BankDetails bankDetails,
PaymentMode paymentMode)
throws AxelorException;
List<MoveLine> getPaymentSchedulerMoveLineToPay(PaymentSchedule paymentSchedule);
void validatePaymentSchedule(PaymentSchedule paymentSchedule) throws AxelorException;
void updateInvoices(PaymentSchedule paymentSchedule);
void updateInvoice(Invoice invoice, PaymentSchedule paymentSchedule);
void cancelPaymentSchedule(PaymentSchedule paymentSchedule);
boolean isLastSchedule(PaymentScheduleLine paymentScheduleLine);
void closePaymentSchedule(PaymentSchedule paymentSchedule) throws AxelorException;
void closePaymentScheduleIfAllPaid(PaymentSchedule paymentSchedule) throws AxelorException;
LocalDate getMostOldDatePaymentScheduleLine(List<PaymentScheduleLine> paymentScheduleLineList);
LocalDate getMostRecentDatePaymentScheduleLine(List<PaymentScheduleLine> paymentScheduleLineList);
void createPaymentScheduleLines(PaymentSchedule paymentSchedule);
void initCollection(PaymentSchedule paymentSchedule);
void toCancelPaymentSchedule(PaymentSchedule paymentSchedule);
/**
* Get partner's bank details.
*
* @param paymentSchedule
* @return
* @throws AxelorException
*/
BankDetails getBankDetails(PaymentSchedule paymentSchedule) throws AxelorException;
/**
* Check total line amount.
*
* @param paymentSchedule
* @throws AxelorException
*/
void checkTotalLineAmount(PaymentSchedule paymentSchedule) throws AxelorException;
/**
* Get next payment schedule line sequence number.
*
* @param paymentSchedule
* @return
*/
int getNextScheduleLineSeq(PaymentSchedule paymentSchedule);
}

View File

@ -0,0 +1,608 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.PaymentMode;
import com.axelor.apps.account.db.PaymentSchedule;
import com.axelor.apps.account.db.PaymentScheduleLine;
import com.axelor.apps.account.db.repo.PaymentScheduleLineRepository;
import com.axelor.apps.account.db.repo.PaymentScheduleRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.PartnerService;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PaymentScheduleServiceImpl implements PaymentScheduleService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected PaymentScheduleLineService paymentScheduleLineService;
protected PaymentScheduleLineRepository paymentScheduleLineRepo;
protected SequenceService sequenceService;
protected PaymentScheduleRepository paymentScheduleRepo;
protected PartnerService partnerService;
protected AppAccountService appAccountService;
@Inject
public PaymentScheduleServiceImpl(
AppAccountService appAccountService,
PaymentScheduleLineService paymentScheduleLineService,
PaymentScheduleLineRepository paymentScheduleLineRepo,
SequenceService sequenceService,
PaymentScheduleRepository paymentScheduleRepo,
PartnerService partnerService) {
this.paymentScheduleLineService = paymentScheduleLineService;
this.paymentScheduleLineRepo = paymentScheduleLineRepo;
this.sequenceService = sequenceService;
this.paymentScheduleRepo = paymentScheduleRepo;
this.partnerService = partnerService;
this.appAccountService = appAccountService;
}
/**
* Création d'un échéancier sans ces lignes.
*
* @param partner Le tiers.
* @param invoices Collection de factures.
* @param company La société.
* @param startDate Date de première échéance.
* @param nbrTerm Nombre d'échéances.
* @return L'échéancier créé.
* @throws AxelorException
*/
@Override
public PaymentSchedule createPaymentSchedule(
Partner partner, Company company, Set<Invoice> invoices, LocalDate startDate, int nbrTerm)
throws AxelorException {
Invoice invoice = null;
PaymentSchedule paymentSchedule =
this.createPaymentSchedule(
partner,
invoice,
company,
appAccountService.getTodayDate(),
startDate,
nbrTerm,
partnerService.getDefaultBankDetails(partner),
partner.getInPaymentMode());
paymentSchedule.getInvoiceSet().addAll(invoices);
return paymentSchedule;
}
/**
* Création d'un échéancier sans ces lignes.
*
* @param partner Le tiers.
* @param invoice Facture globale permettant de définir la facture pour une échéance. L'échéancier
* est automatiquement associé à la facture si celle-ci existe.
* @param company La société.
* @param date Date de création.
* @param startDate Date de première échéance.
* @param nbrTerm Nombre d'échéances.
* @param bankDetails RIB.
* @param paymentMode Mode de paiement.
* @param payerPartner Tiers payeur.
* @param type Type de l'échéancier. <code>0 = paiement</code> <code>1 = mensu masse</code> <code>
* 2 = mensu grand-compte</code>
* @return L'échéancier créé.
* @throws AxelorException
*/
@Override
public PaymentSchedule createPaymentSchedule(
Partner partner,
Invoice invoice,
Company company,
LocalDate date,
LocalDate startDate,
int nbrTerm,
BankDetails bankDetails,
PaymentMode paymentMode)
throws AxelorException {
PaymentSchedule paymentSchedule = new PaymentSchedule();
paymentSchedule.setCompany(company);
paymentSchedule.setPaymentScheduleSeq(this.getPaymentScheduleSequence(company));
paymentSchedule.setCreationDate(date);
paymentSchedule.setStartDate(startDate);
paymentSchedule.setNbrTerm(nbrTerm);
paymentSchedule.setBankDetails(bankDetails);
paymentSchedule.setPaymentMode(paymentMode);
paymentSchedule.setPartner(partner);
if (paymentSchedule.getInvoiceSet() == null) {
paymentSchedule.setInvoiceSet(new HashSet<Invoice>());
} else {
paymentSchedule.getInvoiceSet().clear();
}
if (invoice != null) {
paymentSchedule.addInvoiceSetItem(invoice);
invoice.setPaymentSchedule(paymentSchedule);
}
return paymentSchedule;
}
/**
* Fonction permettant de tester et de récupérer une séquence de prélèvement
*
* @param company Une société
* @param journal Un journal
* @return
* @throws AxelorException
*/
@Override
public String getPaymentScheduleSequence(Company company) throws AxelorException {
String seq = sequenceService.getSequenceNumber(SequenceRepository.PAYMENT_SCHEDULE, company);
if (seq == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
"%s :\n" + I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_5),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
return seq;
}
/**
* Obtenir le total des factures des lignes d'un échéancier.
*
* @param paymentSchedule L'échéancier cible.
* @return Le somme des montants TTC des lignes de l'échéancier.
*/
@Override
public BigDecimal getInvoiceTermTotal(PaymentSchedule paymentSchedule) {
BigDecimal totalAmount = BigDecimal.ZERO;
if (paymentSchedule != null
&& paymentSchedule.getPaymentScheduleLineList() != null
&& !paymentSchedule.getPaymentScheduleLineList().isEmpty()) {
for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
if (paymentScheduleLine.getInTaxAmount() != null) {
log.debug(
"Somme TTC des lignes de l'échéancier {} : total = {}, ajout = {}",
new Object[] {
paymentSchedule.getPaymentScheduleSeq(),
totalAmount,
paymentScheduleLine.getInTaxAmount()
});
totalAmount = totalAmount.add(paymentScheduleLine.getInTaxAmount());
}
}
}
log.debug(
"Obtention de la somme TTC des lignes de l'échéancier {} : {}",
new Object[] {paymentSchedule.getPaymentScheduleSeq(), totalAmount});
return totalAmount;
}
/**
* Mise à jour d'un échéancier avec un nouveau montant d'échéance.
*
* @param paymentSchedule L'échéancier cible.
* @param inTaxTotal Nouveau montant d'une échéance.
*/
@Override
@Transactional
public void updatePaymentSchedule(PaymentSchedule paymentSchedule, BigDecimal inTaxTotal) {
log.debug(
"Mise à jour de l'échéancier {} : {}",
new Object[] {paymentSchedule.getPaymentScheduleSeq(), inTaxTotal});
for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
if (paymentScheduleLine.getStatusSelect() == PaymentScheduleLineRepository.STATUS_IN_PROGRESS
&& !paymentScheduleLine.getRejectedOk()) {
log.debug("Mise à jour de la ligne {} ", paymentScheduleLine.getName());
paymentScheduleLine.setInTaxAmount(inTaxTotal);
}
}
paymentScheduleRepo.save(paymentSchedule);
}
/**
* Création d'un échéancier avec ces lignes.
*
* @param company La société.
* @param date Date de création.
* @param firstTermDate Date de première échéance.
* @param initialInTaxAmount Montant d'une échéance.
* @param nbrTerm Nombre d'échéances.
* @param bankDetails RIB.
* @param paymentMode Mode de paiement.
* @param payerPartner Tiers payeur.
* @return L'échéancier créé.
* @throws AxelorException
*/
@Override
public PaymentSchedule createPaymentSchedule(
Partner partner,
Company company,
LocalDate date,
LocalDate firstTermDate,
BigDecimal initialInTaxAmount,
int nbrTerm,
BankDetails bankDetails,
PaymentMode paymentMode)
throws AxelorException {
Invoice invoice = null;
PaymentSchedule paymentSchedule =
this.createPaymentSchedule(
partner, invoice, company, date, firstTermDate, nbrTerm, bankDetails, paymentMode);
paymentSchedule.setPaymentScheduleLineList(new ArrayList<PaymentScheduleLine>());
for (int term = 1; term < nbrTerm + 1; term++) {
paymentSchedule
.getPaymentScheduleLineList()
.add(
paymentScheduleLineService.createPaymentScheduleLine(
paymentSchedule, initialInTaxAmount, term, firstTermDate.plusMonths(term - 1)));
}
return paymentSchedule;
}
/**
* This method is used to get the movelines to be paid based on a paymentSchedule It loops on the
* invoice M2M content and gets the movelines which are to pay
*
* @param ps
* @return
*/
@Override
public List<MoveLine> getPaymentSchedulerMoveLineToPay(PaymentSchedule paymentSchedule) {
log.debug("In getPaymentSchedulerMoveLineToPay ....");
List<MoveLine> moveLines = new ArrayList<MoveLine>();
for (Invoice invoice : paymentSchedule.getInvoiceSet()) {
if (invoice.getCompanyInTaxTotalRemaining().compareTo(BigDecimal.ZERO) > 0
&& invoice.getMove() != null
&& invoice.getMove().getMoveLineList() != null) {
for (MoveLine moveLine : invoice.getMove().getMoveLineList()) {
if (moveLine.getAccount().getUseForPartnerBalance()
&& moveLine.getAmountRemaining().compareTo(BigDecimal.ZERO) > 0
&& moveLine.getDebit().compareTo(BigDecimal.ZERO) > 0) {
moveLines.add(moveLine);
}
}
}
}
log.debug("End getPaymentSchedulerMoveLineToPay.");
return moveLines;
}
@Override
public void checkTotalLineAmount(PaymentSchedule paymentSchedule) throws AxelorException {
BigDecimal total = getInvoiceTermTotal(paymentSchedule);
if (total.compareTo(paymentSchedule.getInTaxAmount()) != 0) {
throw new AxelorException(
paymentSchedule,
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_LINE_AMOUNT_MISMATCH),
total,
paymentSchedule.getInTaxAmount());
}
}
/**
* Permet de valider un échéancier.
*
* @param paymentSchedule
* @throws AxelorException
*/
@Override
@Transactional(rollbackOn = {Exception.class})
public void validatePaymentSchedule(PaymentSchedule paymentSchedule) throws AxelorException {
log.debug("Validation de l'échéancier {}", paymentSchedule.getPaymentScheduleSeq());
if (paymentSchedule.getPaymentScheduleLineList() == null
|| paymentSchedule.getPaymentScheduleLineList().isEmpty()) {
throw new AxelorException(
paymentSchedule,
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.PAYMENT_SCHEDULE_6),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
paymentSchedule.getPaymentScheduleSeq());
}
checkTotalLineAmount(paymentSchedule);
for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_IN_PROGRESS);
}
this.updateInvoices(paymentSchedule);
paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CONFIRMED);
}
@Override
public void updateInvoices(PaymentSchedule paymentSchedule) {
if (paymentSchedule.getInvoiceSet() != null) {
List<MoveLine> moveLineInvoiceToPay = this.getPaymentSchedulerMoveLineToPay(paymentSchedule);
for (MoveLine moveLineInvoice : moveLineInvoiceToPay) {
moveLineInvoice.getMove().setIgnoreInDebtRecoveryOk(true);
this.updateInvoice(moveLineInvoice.getMove().getInvoice(), paymentSchedule);
}
}
}
@Override
public void updateInvoice(Invoice invoice, PaymentSchedule paymentSchedule) {
invoice.setSchedulePaymentOk(true);
invoice.setPaymentSchedule(paymentSchedule);
}
/**
* Methode qui annule un échéancier
*
* @param paymentSchedule
*/
@Override
public void cancelPaymentSchedule(PaymentSchedule paymentSchedule) {
// L'échéancier est passé à annulé
paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CANCELED);
for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
// Si l'échéance n'est pas complètement payée
if (paymentScheduleLine.getInTaxAmountPaid().compareTo(paymentScheduleLine.getInTaxAmount())
!= 0) {
// L'échéance est passée à cloturé
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_CLOSED);
}
}
for (Invoice invoice : paymentSchedule.getInvoiceSet()) {
// L'échéancier n'est plus selectionné sur la facture
invoice.setPaymentSchedule(null);
// L'échéancier est assigné dans un nouveau champs afin de garder un lien invisble pour
// l'utilisateur, mais utilisé pour le passage en irrécouvrable
invoice.setCanceledPaymentSchedule(paymentSchedule);
invoice.setSchedulePaymentOk(false);
}
}
/**
* Methode permettant de savoir si l'échéance passée en paramètre est la dernière de l'échéancier
*
* @param paymentScheduleLine
* @return
*/
@Override
public boolean isLastSchedule(PaymentScheduleLine paymentScheduleLine) {
if (paymentScheduleLine != null) {
if (paymentScheduleLineRepo
.all()
.filter(
"self.paymentSchedule = ?1 and self.scheduleDate > ?2 and self.statusSelect = ?3",
paymentScheduleLine.getPaymentSchedule(),
paymentScheduleLine.getScheduleDate(),
PaymentScheduleLineRepository.STATUS_IN_PROGRESS)
.fetchOne()
== null) {
log.debug("Dernière échéance");
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* Méthode permettant de passer les statuts des lignes d'échéances et de l'échéancier à 'clo' ie
* cloturé
*
* @param invoice Une facture de fin de cycle
* @throws AxelorException
*/
@Override
public void closePaymentSchedule(PaymentSchedule paymentSchedule) throws AxelorException {
log.debug("Cloture de l'échéancier");
// On récupère un statut cloturé, afin de pouvoir changer l'état des lignes d'échéanciers
for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
paymentScheduleLine.setStatusSelect(PaymentScheduleLineRepository.STATUS_CLOSED);
}
paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CLOSED);
}
/**
* Close payment schedule if all paid.
*
* @param paymentSchedule
* @throws AxelorException
*/
@Override
public void closePaymentScheduleIfAllPaid(PaymentSchedule paymentSchedule)
throws AxelorException {
if (paymentSchedule.getPaymentScheduleLineList() == null) {
return;
}
for (PaymentScheduleLine paymentScheduleLine : paymentSchedule.getPaymentScheduleLineList()) {
if (paymentScheduleLine.getStatusSelect() < PaymentScheduleLineRepository.STATUS_VALIDATED) {
return;
}
}
paymentSchedule.setStatusSelect(PaymentScheduleRepository.STATUS_CLOSED);
}
@Override
public LocalDate getMostOldDatePaymentScheduleLine(
List<PaymentScheduleLine> paymentScheduleLineList) {
LocalDate minPaymentScheduleLineDate = LocalDate.now();
if (paymentScheduleLineList != null && !paymentScheduleLineList.isEmpty()) {
for (PaymentScheduleLine paymentScheduleLine : paymentScheduleLineList) {
if (minPaymentScheduleLineDate.isAfter(paymentScheduleLine.getScheduleDate())) {
minPaymentScheduleLineDate = paymentScheduleLine.getScheduleDate();
}
}
} else {
minPaymentScheduleLineDate = null;
}
return minPaymentScheduleLineDate;
}
@Override
public LocalDate getMostRecentDatePaymentScheduleLine(
List<PaymentScheduleLine> paymentScheduleLineList) {
LocalDate minPaymentScheduleLineDate = LocalDate.now();
if (paymentScheduleLineList != null && !paymentScheduleLineList.isEmpty()) {
for (PaymentScheduleLine paymentScheduleLine : paymentScheduleLineList) {
if (minPaymentScheduleLineDate.isBefore(paymentScheduleLine.getScheduleDate())) {
minPaymentScheduleLineDate = paymentScheduleLine.getScheduleDate();
}
}
} else {
minPaymentScheduleLineDate = null;
}
return minPaymentScheduleLineDate;
}
// Transactional
/**
* Créer des lignes d'échéancier à partir des lignes de factures de celui-ci.
*
* @param paymentSchedule
* @throws AxelorException
*/
@Override
@Transactional
public void createPaymentScheduleLines(PaymentSchedule paymentSchedule) {
this.initCollection(paymentSchedule);
paymentSchedule
.getPaymentScheduleLineList()
.addAll(paymentScheduleLineService.createPaymentScheduleLines(paymentSchedule));
paymentScheduleRepo.save(paymentSchedule);
}
@Override
public void initCollection(PaymentSchedule paymentSchedule) {
if (paymentSchedule.getPaymentScheduleLineList() == null) {
paymentSchedule.setPaymentScheduleLineList(new ArrayList<PaymentScheduleLine>());
} else {
paymentSchedule.getPaymentScheduleLineList().clear();
}
}
@Override
@Transactional
public void toCancelPaymentSchedule(PaymentSchedule paymentSchedule) {
this.cancelPaymentSchedule(paymentSchedule);
paymentScheduleRepo.save(paymentSchedule);
}
@Override
public BankDetails getBankDetails(PaymentSchedule paymentSchedule) throws AxelorException {
BankDetails bankDetails = paymentSchedule.getBankDetails();
if (bankDetails != null) {
return bankDetails;
}
Partner partner = paymentSchedule.getPartner();
Preconditions.checkNotNull(partner);
bankDetails = partnerService.getDefaultBankDetails(partner);
if (bankDetails != null) {
return bankDetails;
}
throw new AxelorException(
partner,
TraceBackRepository.CATEGORY_MISSING_FIELD,
I18n.get(IExceptionMessage.PARTNER_BANK_DETAILS_MISSING),
partner.getName());
}
@Override
public int getNextScheduleLineSeq(PaymentSchedule paymentSchedule) {
List<PaymentScheduleLine> paymentScheduleLines =
MoreObjects.firstNonNull(
paymentSchedule.getPaymentScheduleLineList(), Collections.emptyList());
int currentMaxSequenceNumber =
paymentScheduleLines
.stream()
.mapToInt(PaymentScheduleLine::getScheduleLineSeq)
.max()
.orElse(0);
return currentMaxSequenceNumber + 1;
}
}

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.account.service;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.base.db.Period;
import com.axelor.db.Query;
public interface PeriodServiceAccount {
public Query<Move> getMoveListToValidateQuery(Period period);
}

View File

@ -0,0 +1,71 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.service.move.MoveValidateService;
import com.axelor.apps.base.db.Period;
import com.axelor.apps.base.db.repo.PeriodRepository;
import com.axelor.apps.base.db.repo.YearRepository;
import com.axelor.apps.base.service.AdjustHistoryService;
import com.axelor.apps.base.service.PeriodServiceImpl;
import com.axelor.db.Query;
import com.axelor.exception.AxelorException;
import com.google.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class PeriodServiceAccountImpl extends PeriodServiceImpl implements PeriodServiceAccount {
protected MoveValidateService moveValidateService;
protected MoveRepository moveRepository;
@Inject
public PeriodServiceAccountImpl(
PeriodRepository periodRepo,
AdjustHistoryService adjustHistoryService,
MoveValidateService moveValidateService,
MoveRepository moveRepository) {
super(periodRepo, adjustHistoryService);
this.moveValidateService = moveValidateService;
this.moveRepository = moveRepository;
}
public void close(Period period) throws AxelorException {
if (period.getYear().getTypeSelect() == YearRepository.TYPE_FISCAL) {
moveValidateService.validateMultiple(getMoveListToValidateQuery(period));
period = periodRepo.find(period.getId());
}
super.close(period);
}
public Query<Move> getMoveListToValidateQuery(Period period) {
return moveRepository
.all()
.filter(
"self.period.id = ?1 AND (self.statusSelect NOT IN (?2,?3, ?4) OR (self.statusSelect = ?2 AND (self.archived = false OR self.archived is null)))",
period.getId(),
MoveRepository.STATUS_NEW,
MoveRepository.STATUS_VALIDATED,
MoveRepository.STATUS_CANCELED)
.order("date")
.order("id");
}
}

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.account.service;
import com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.exception.AxelorException;
public interface ReconcileGroupSequenceService {
/**
* Set sequence for reconcile group, based on the status of the reconcile group, the sequence can
* be draft or final.
*/
void fillCodeFromSequence(ReconcileGroup reconcileGroup) throws AxelorException;
}

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.account.service;
import com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.apps.account.db.repo.ReconcileGroupRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
public class ReconcileGroupSequenceServiceImpl implements ReconcileGroupSequenceService {
@Override
public void fillCodeFromSequence(ReconcileGroup reconcileGroup) throws AxelorException {
String sequenceCode;
String exceptionMessage;
if (reconcileGroup.getStatusSelect() == ReconcileGroupRepository.STATUS_FINAL) {
sequenceCode = SequenceRepository.RECONCILE_GROUP_FINAL;
exceptionMessage = IExceptionMessage.RECONCILE_GROUP_NO_FINAL_SEQUENCE;
} else {
sequenceCode = SequenceRepository.RECONCILE_GROUP_DRAFT;
exceptionMessage = IExceptionMessage.RECONCILE_GROUP_NO_TEMP_SEQUENCE;
}
String code =
Beans.get(SequenceService.class)
.getSequenceNumber(sequenceCode, reconcileGroup.getCompany());
if (code == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(exceptionMessage),
reconcileGroup);
}
reconcileGroup.setCode(code);
}
}

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.account.service;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.apps.base.db.Company;
import com.axelor.exception.AxelorException;
import java.util.List;
import java.util.Optional;
public interface ReconcileGroupService {
/**
* Validate the given reconcile group. A reconcile Group can be validated if it is not empty and
* its lines are balanced.
*
* @param reconcileGroup a reconcile group.
* @param reconcileList a list of reconcile.
* @throws AxelorException if the reconcile list is empty.
*/
void validate(ReconcileGroup reconcileGroup, List<Reconcile> reconcileList)
throws AxelorException;
/**
* Check if the given reconcile lines are balanced.
*
* @param reconcileList a list of reconcile.
*/
boolean isBalanced(List<Reconcile> reconcileList) throws AxelorException;
/**
* Call {@link ReconcileGroupService#findOrMergeGroup} to get a reconcile group. If not found,
* create one with {@link ReconcileGroupService#createReconcileGroup}
*
* @param reconcile a confirmed reconcile
* @return the created or found group.
*/
ReconcileGroup findOrCreateGroup(Reconcile reconcile);
/**
* Find the corresponding group for a given reconcile. If two or more reconcile group are found,
* then return the merge between them.
*
* @param reconcile a confirmed reconcile.
* @return an optional with the reconcile group if it was found. Else an empty optional.
*/
Optional<ReconcileGroup> findOrMergeGroup(Reconcile reconcile);
/**
* Merge reconcile groups into one. The created reconcile group will have a new sequence and all
* reconcile lines from the groups.
*
* @param reconcileGroupList a non empty list of reconcile group to merge.
* @return the created reconcile group.
*/
ReconcileGroup mergeReconcileGroups(List<ReconcileGroup> reconcileGroupList);
/**
* Create a reconcile group with the given reconcile.
*
* @param company a confirmed reconcile.
* @return a new reconcile group.
*/
ReconcileGroup createReconcileGroup(Company company);
/**
* Add a reconcile to a group and validate the group if it is balanced.
*
* @param reconcileGroup a reconcileGroup.
* @param reconcile a reconcile.
*/
void addAndValidate(ReconcileGroup reconcileGroup, Reconcile reconcile) throws AxelorException;
/**
* Add a reconcile to a group and validate the group if it is balanced.
*
* @param reconcileGroup a reconcileGroup.
* @param List<reconcile> a list reconcile.
*/
public void addAllAndValidate(ReconcileGroup reconcileGroup, List<Reconcile> reconcileList)
throws AxelorException;
/**
* Add the reconcile and its move line to the reconcile group.
*
* @param reconcileGroup a reconcileGroup.
* @param reconcile the confirmed reconcile to be added.
*/
void addToReconcileGroup(ReconcileGroup reconcileGroup, Reconcile reconcile);
/**
* Remove a reconcile from a reconcile group then update the group.
*
* @param reconcile a reconcile with a reconcile group.
*/
void remove(Reconcile reconcile) throws AxelorException;
/**
* Update the status and the sequence of a reconcile group.
*
* @param reconcileGroup
*/
void updateStatus(ReconcileGroup reconcileGroup) throws AxelorException;
/**
* Unletter every moveline and update unlettering date.
*
* @param reconcileGroup
* @throws AxelorException
*/
void unletter(ReconcileGroup reconcileGroup) throws AxelorException;
}

View File

@ -0,0 +1,290 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.ReconcileGroupRepository;
import com.axelor.apps.account.db.repo.ReconcileRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
public class ReconcileGroupServiceImpl implements ReconcileGroupService {
protected ReconcileGroupRepository reconcileGroupRepository;
protected ReconcileRepository reconcileRepository;
protected MoveLineRepository moveLineRepository;
protected ReconcileService reconcileService;
protected AppBaseService appBaseService;
protected ReconcileGroupSequenceService reconcileGroupSequenceService;
@Inject
public ReconcileGroupServiceImpl(
ReconcileGroupRepository reconcileGroupRepository,
ReconcileRepository reconcileRepository,
MoveLineRepository moveLineRepository,
ReconcileService reconcileService,
AppBaseService appBaseService,
ReconcileGroupSequenceService reconcileGroupSequenceService) {
this.reconcileGroupRepository = reconcileGroupRepository;
this.reconcileRepository = reconcileRepository;
this.moveLineRepository = moveLineRepository;
this.reconcileService = reconcileService;
this.appBaseService = appBaseService;
this.reconcileGroupSequenceService = reconcileGroupSequenceService;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void validate(ReconcileGroup reconcileGroup, List<Reconcile> reconcileList)
throws AxelorException {
if (CollectionUtils.isEmpty(reconcileList)) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.RECONCILE_GROUP_VALIDATION_NO_LINES),
reconcileGroup);
}
reconcileGroup.setStatusSelect(ReconcileGroupRepository.STATUS_FINAL);
reconcileGroup.setDateOfLettering(appBaseService.getTodayDate());
reconcileGroupSequenceService.fillCodeFromSequence(reconcileGroup);
}
@Override
public boolean isBalanced(List<Reconcile> reconcileList) {
List<MoveLine> debitMoveLineList =
reconcileList
.stream()
.map(Reconcile::getDebitMoveLine)
.distinct()
.collect(Collectors.toList());
List<MoveLine> creditMoveLineList =
reconcileList
.stream()
.map(Reconcile::getCreditMoveLine)
.distinct()
.collect(Collectors.toList());
List<Account> accountList =
debitMoveLineList
.stream()
.map(MoveLine::getAccount)
.distinct()
.collect(Collectors.toList());
accountList.addAll(
creditMoveLineList
.stream()
.map(MoveLine::getAccount)
.distinct()
.collect(Collectors.toList()));
for (Account account : accountList) {
BigDecimal totalDebit =
debitMoveLineList
.stream()
.filter(moveLine -> moveLine.getAccount().equals(account))
.map(MoveLine::getDebit)
.reduce(BigDecimal::add)
.orElse(BigDecimal.ZERO);
BigDecimal totalCredit =
creditMoveLineList
.stream()
.filter(moveLine -> moveLine.getAccount().equals(account))
.map(MoveLine::getCredit)
.reduce(BigDecimal::add)
.orElse(BigDecimal.ZERO);
if (totalDebit.compareTo(totalCredit) != 0) {
return false;
}
}
return true;
}
@Override
public ReconcileGroup findOrCreateGroup(Reconcile reconcile) {
return findOrMergeGroup(reconcile)
.orElseGet(() -> createReconcileGroup(reconcile.getCompany()));
}
@Override
public Optional<ReconcileGroup> findOrMergeGroup(Reconcile reconcile) {
List<ReconcileGroup> otherReconcileGroupList;
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
otherReconcileGroupList = new ArrayList<>();
if (debitMoveLine.getReconcileGroup() != null) {
otherReconcileGroupList.add(debitMoveLine.getReconcileGroup());
}
if (creditMoveLine.getReconcileGroup() != null) {
otherReconcileGroupList.add(creditMoveLine.getReconcileGroup());
}
otherReconcileGroupList =
otherReconcileGroupList.stream().distinct().collect(Collectors.toList());
if (otherReconcileGroupList.isEmpty()) {
return Optional.empty();
} else if (otherReconcileGroupList.size() == 1) {
return Optional.of(otherReconcileGroupList.get(0));
} else {
return Optional.of(mergeReconcileGroups(otherReconcileGroupList));
}
}
@Override
@Transactional
public ReconcileGroup mergeReconcileGroups(List<ReconcileGroup> reconcileGroupList) {
Company company = reconcileGroupList.get(0).getCompany();
ReconcileGroup reconcileGroup = createReconcileGroup(company);
List<Reconcile> reconcileList =
reconcileRepository
.all()
.filter("self.reconcileGroup.id IN (:reconcileGroupIds)")
.bind(
"reconcileGroupIds",
reconcileGroupList.stream().map(ReconcileGroup::getId).collect(Collectors.toList()))
.fetch();
reconcileList.forEach(reconcile -> addToReconcileGroup(reconcileGroup, reconcile));
for (ReconcileGroup toDeleteReconcileGroup : reconcileGroupList) {
reconcileGroupRepository.remove(toDeleteReconcileGroup);
}
return reconcileGroupRepository.save(reconcileGroup);
}
@Override
@Transactional
public ReconcileGroup createReconcileGroup(Company company) {
ReconcileGroup reconcileGroup = new ReconcileGroup();
reconcileGroup.setCompany(company);
return reconcileGroupRepository.save(reconcileGroup);
}
@Override
public void addAndValidate(ReconcileGroup reconcileGroup, Reconcile reconcile)
throws AxelorException {
List<Reconcile> reconcileList = this.getReconcileList(reconcileGroup);
reconcileList.add(reconcile);
addToReconcileGroup(reconcileGroup, reconcile);
if (isBalanced(reconcileList)) {
validate(reconcileGroup, reconcileList);
}
}
@Override
public void addAllAndValidate(ReconcileGroup reconcileGroup, List<Reconcile> reconcileList)
throws AxelorException {
for (Reconcile reconcile : reconcileList) {
addToReconcileGroup(reconcileGroup, reconcile);
}
if (isBalanced(reconcileList)) {
validate(reconcileGroup, reconcileList);
}
}
@Override
public void addToReconcileGroup(ReconcileGroup reconcileGroup, Reconcile reconcile) {
reconcile.setReconcileGroup(reconcileGroup);
reconcile.getDebitMoveLine().setReconcileGroup(reconcileGroup);
reconcile.getCreditMoveLine().setReconcileGroup(reconcileGroup);
}
@Override
public void remove(Reconcile reconcile) throws AxelorException {
ReconcileGroup reconcileGroup = reconcile.getReconcileGroup();
// update move lines
List<MoveLine> moveLineToRemoveList =
moveLineRepository.findByReconcileGroup(reconcileGroup).fetch();
moveLineToRemoveList.forEach(moveLine -> moveLine.setReconcileGroup(null));
List<Reconcile> reconcileList = this.getReconcileList(reconcileGroup);
reconcileList
.stream()
.map(Reconcile::getDebitMoveLine)
.forEach(moveLine -> moveLine.setReconcileGroup(reconcileGroup));
reconcileList
.stream()
.map(Reconcile::getCreditMoveLine)
.forEach(moveLine -> moveLine.setReconcileGroup(reconcileGroup));
// update status
updateStatus(reconcileGroup);
}
@Override
public void updateStatus(ReconcileGroup reconcileGroup) throws AxelorException {
List<Reconcile> reconcileList = this.getReconcileList(reconcileGroup);
int status = reconcileGroup.getStatusSelect();
if (CollectionUtils.isNotEmpty(reconcileList)
&& isBalanced(reconcileList)
&& status == ReconcileGroupRepository.STATUS_TEMPORARY) {
validate(reconcileGroup, reconcileList);
} else if (status == ReconcileGroupRepository.STATUS_FINAL) {
// it is not balanced or the collection is empty.
if (CollectionUtils.isEmpty(reconcileList)) {
reconcileGroup.setStatusSelect(ReconcileGroupRepository.STATUS_UNLETTERED);
reconcileGroup.setUnletteringDate(appBaseService.getTodayDate());
reconcileGroupRepository.save(reconcileGroup);
} else {
reconcileGroup.setStatusSelect(ReconcileGroupRepository.STATUS_TEMPORARY);
reconcileGroupSequenceService.fillCodeFromSequence(reconcileGroup);
}
}
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void unletter(ReconcileGroup reconcileGroup) throws AxelorException {
List<Reconcile> reconcileList = this.getReconcileList(reconcileGroup);
for (Reconcile reconcile : reconcileList) {
reconcileService.unreconcile(reconcile);
}
reconcileGroup.setUnletteringDate(appBaseService.getTodayDate());
reconcileGroup.setStatusSelect(ReconcileGroupRepository.STATUS_UNLETTERED);
reconcileGroupRepository.save(reconcileGroup);
}
protected List<Reconcile> getReconcileList(ReconcileGroup reconcileGroup) {
return reconcileRepository
.all()
.filter("self.reconcileGroup.id = :reconcileGroupId AND self.statusSelect = :confirmed")
.bind("reconcileGroupId", reconcileGroup.getId())
.bind("confirmed", ReconcileRepository.STATUS_CONFIRMED)
.fetch();
}
}

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.account.service;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.repo.ReconcileRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.common.base.Strings;
import com.google.inject.Inject;
public class ReconcileSequenceService {
protected SequenceService sequenceService;
@Inject
public ReconcileSequenceService(SequenceService sequenceService) {
this.sequenceService = sequenceService;
}
public void setSequence(Reconcile reconcile) throws AxelorException {
reconcile.setReconcileSeq(this.getSequence(reconcile));
}
protected String getSequence(Reconcile reconcile) throws AxelorException {
SequenceService sequenceService = Beans.get(SequenceService.class);
String seq =
sequenceService.getSequenceNumber(
SequenceRepository.RECONCILE, reconcile.getDebitMoveLine().getMove().getCompany());
if (seq == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.RECONCILE_6),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
reconcile.getCompany().getName());
}
return seq;
}
public void setDraftSequence(Reconcile reconcile) throws AxelorException {
if (reconcile.getId() != null
&& Strings.isNullOrEmpty(reconcile.getReconcileSeq())
&& reconcile.getStatusSelect() == ReconcileRepository.STATUS_DRAFT) {
reconcile.setReconcileSeq(sequenceService.getDraftSequenceNumber(reconcile));
}
}
}

View File

@ -0,0 +1,81 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import com.google.inject.persist.Transactional;
import java.math.BigDecimal;
import java.util.List;
public interface ReconcileService {
@Transactional
public Reconcile createReconcile(
MoveLine debitMoveLine,
MoveLine creditMoveLine,
BigDecimal amount,
boolean canBeZeroBalanceOk);
@Transactional(rollbackOn = {Exception.class})
public Reconcile confirmReconcile(Reconcile reconcile, boolean updateInvoicePayments)
throws AxelorException;
@Transactional(rollbackOn = {Exception.class})
public Reconcile confirmPaymentVoucherReconcile(
Reconcile reconcile, boolean updateInvoicePayments) throws AxelorException;
public void reconcilePreconditions(Reconcile reconcile) throws AxelorException;
public void updatePartnerAccountingSituation(Reconcile reconcile) throws AxelorException;
public List<Partner> getPartners(Reconcile reconcile);
public Reconcile reconcile(
MoveLine debitMoveLine,
MoveLine creditMoveLine,
boolean canBeZeroBalanceOk,
boolean updateInvoicePayments)
throws AxelorException;
@Transactional(rollbackOn = {Exception.class})
public void unreconcile(Reconcile reconcile) throws AxelorException;
@Transactional(rollbackOn = {Exception.class})
public void canBeZeroBalance(Reconcile reconcile) throws AxelorException;
public void balanceCredit(MoveLine creditMoveLine) throws AxelorException;
public List<Reconcile> getReconciles(MoveLine moveLine);
/**
* Add a reconcile to an existing or created reconcile group.
*
* @param reconcile a confirmed reconcile.
*/
void addToReconcileGroup(Reconcile reconcile) throws AxelorException;
public static boolean isReconcilable(MoveLine acc1, MoveLine acc2) {
return acc1.getAccount().getReconcileOk()
&& acc2.getAccount().getReconcileOk()
&& (acc1.getAccount().equals(acc2.getAccount())
|| acc1.getAccount().getCompatibleAccountSet().contains(acc2.getAccount()));
}
}

View File

@ -0,0 +1,620 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.InvoicePayment;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.ReconcileGroup;
import com.axelor.apps.account.db.repo.InvoicePaymentRepository;
import com.axelor.apps.account.db.repo.ReconcileRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.move.MoveAdjustementService;
import com.axelor.apps.account.service.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveToolService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCancelService;
import com.axelor.apps.account.service.payment.invoice.payment.InvoicePaymentCreateService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReconcileServiceImpl implements ReconcileService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected MoveToolService moveToolService;
protected AccountCustomerService accountCustomerService;
protected AccountConfigService accountConfigService;
protected ReconcileRepository reconcileRepository;
protected MoveAdjustementService moveAdjustementService;
protected ReconcileSequenceService reconcileSequenceService;
protected InvoicePaymentCreateService invoicePaymentCreateService;
protected InvoicePaymentCancelService invoicePaymentCancelService;
protected MoveLineService moveLineService;
@Inject
public ReconcileServiceImpl(
MoveToolService moveToolService,
AccountCustomerService accountCustomerService,
AccountConfigService accountConfigService,
ReconcileRepository reconcileRepository,
MoveAdjustementService moveAdjustementService,
ReconcileSequenceService reconcileSequenceService,
InvoicePaymentCancelService invoicePaymentCancelService,
InvoicePaymentCreateService invoicePaymentCreateService,
MoveLineService moveLineService) {
this.moveToolService = moveToolService;
this.accountCustomerService = accountCustomerService;
this.accountConfigService = accountConfigService;
this.reconcileRepository = reconcileRepository;
this.moveAdjustementService = moveAdjustementService;
this.reconcileSequenceService = reconcileSequenceService;
this.invoicePaymentCancelService = invoicePaymentCancelService;
this.invoicePaymentCreateService = invoicePaymentCreateService;
this.moveLineService = moveLineService;
}
/**
* Permet de créer une réconciliation en passant les paramètres qu'il faut
*
* @param lineDebit Une ligne d'écriture au débit
* @param lineCredit Une ligne d'écriture au crédit
* @param amount Le montant à reconciler
* @param canBeZeroBalanceOk Peut être soldé?
* @return Une reconciliation
*/
@Transactional
public Reconcile createReconcile(
MoveLine debitMoveLine,
MoveLine creditMoveLine,
BigDecimal amount,
boolean canBeZeroBalanceOk) {
if (ReconcileService.isReconcilable(debitMoveLine, creditMoveLine)
&& amount.compareTo(BigDecimal.ZERO) > 0) {
log.debug(
"Create Reconcile (Company : {}, Debit MoveLine : {}, Credit MoveLine : {}, Amount : {}, Can be zero balance ? {} )",
debitMoveLine.getMove().getCompany(),
debitMoveLine.getName(),
creditMoveLine.getName(),
amount,
canBeZeroBalanceOk);
Reconcile reconcile =
new Reconcile(
debitMoveLine.getMove().getCompany(),
amount.setScale(2, RoundingMode.HALF_EVEN),
debitMoveLine,
creditMoveLine,
ReconcileRepository.STATUS_DRAFT,
canBeZeroBalanceOk);
if (!moveToolService.isDebitMoveLine(debitMoveLine)) {
reconcile.setDebitMoveLine(creditMoveLine);
reconcile.setCreditMoveLine(debitMoveLine);
}
return reconcileRepository.save(reconcile);
}
return null;
}
/**
* Permet de confirmer une réconciliation On ne peut réconcilier que des moveLine ayant le même
* compte
*
* @param reconcile Une reconciliation
* @return L'etat de la reconciliation
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public Reconcile confirmReconcile(Reconcile reconcile, boolean updateInvoicePayments)
throws AxelorException {
this.reconcilePreconditions(reconcile);
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
// Add the reconciled amount to the reconciled amount in the move line
creditMoveLine.setAmountPaid(creditMoveLine.getAmountPaid().add(reconcile.getAmount()));
debitMoveLine.setAmountPaid(debitMoveLine.getAmountPaid().add(reconcile.getAmount()));
reconcile = reconcileRepository.save(reconcile);
reconcile.setStatusSelect(ReconcileRepository.STATUS_CONFIRMED);
if (reconcile.getCanBeZeroBalanceOk()) {
// Alors nous utilisons la règle de gestion consitant à imputer l'écart sur un compte
// transitoire si le seuil est respecté
canBeZeroBalance(reconcile);
}
reconcile.setReconciliationDate(LocalDate.now());
reconcileSequenceService.setSequence(reconcile);
this.updatePartnerAccountingSituation(reconcile);
this.updateInvoiceCompanyInTaxTotalRemaining(reconcile);
this.udpatePaymentTax(reconcile);
if (updateInvoicePayments) {
this.updateInvoicePayments(reconcile);
}
// this.addToReconcileGroup(reconcile);
return reconcileRepository.save(reconcile);
}
public void addAllToReconcileGroup(List<Reconcile> reconciles) throws AxelorException {
ReconcileGroupService reconcileGroupService = Beans.get(ReconcileGroupService.class);
ReconcileGroup reconcileGroup = reconcileGroupService.findOrCreateGroup(reconciles.get(0));
reconcileGroupService.addAllAndValidate(reconcileGroup, reconciles);
for (Reconcile reconcile : reconciles) {
this.confirmReconcile(reconcile, true);
}
}
@Override
public void addToReconcileGroup(Reconcile reconcile) throws AxelorException {
ReconcileGroupService reconcileGroupService = Beans.get(ReconcileGroupService.class);
ReconcileGroup reconcileGroup = reconcileGroupService.findOrCreateGroup(reconcile);
reconcileGroupService.addAndValidate(reconcileGroup, reconcile);
}
public void reconcilePreconditions(Reconcile reconcile) throws AxelorException {
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
if (debitMoveLine == null || creditMoveLine == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.RECONCILE_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION));
}
// Check if move lines companies are the same as the reconcile company
Company reconcileCompany = reconcile.getCompany();
Company debitMoveLineCompany = debitMoveLine.getMove().getCompany();
Company creditMoveLineCompany = creditMoveLine.getMove().getCompany();
if (!debitMoveLineCompany.equals(reconcileCompany)
&& !creditMoveLineCompany.equals(reconcileCompany)) {
throw new AxelorException(
String.format(
I18n.get(IExceptionMessage.RECONCILE_7),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
debitMoveLineCompany,
creditMoveLineCompany,
reconcileCompany),
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR);
}
// Check if move lines accounts are the same (debit and credit)
if (!creditMoveLine.getAccount().equals(debitMoveLine.getAccount())) {
log.debug(
"Compte ligne de credit : {} , Compte ligne de debit : {}",
creditMoveLine.getAccount(),
debitMoveLine.getAccount());
// Check if move lines accounts are compatible
if (!debitMoveLine
.getAccount()
.getCompatibleAccountSet()
.contains(creditMoveLine.getAccount())) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.RECONCILE_2),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION));
}
}
// Check if the amount to reconcile is != zero
if (reconcile.getAmount() == null || reconcile.getAmount().compareTo(BigDecimal.ZERO) == 0) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.RECONCILE_4),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
reconcile.getReconcileSeq(),
debitMoveLine.getName(),
debitMoveLine.getAccount().getLabel(),
creditMoveLine.getName(),
creditMoveLine.getAccount().getLabel());
}
if ((reconcile
.getAmount()
.compareTo(creditMoveLine.getCredit().subtract(creditMoveLine.getAmountPaid()))
> 0
|| (reconcile
.getAmount()
.compareTo(debitMoveLine.getDebit().subtract(debitMoveLine.getAmountPaid()))
> 0))) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.RECONCILE_5) + " " + I18n.get(IExceptionMessage.RECONCILE_3),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
reconcile.getReconcileSeq(),
reconcile.getAmount(),
debitMoveLine.getName(),
debitMoveLine.getAccount().getLabel(),
debitMoveLine.getDebit().subtract(debitMoveLine.getAmountPaid()),
creditMoveLine.getName(),
creditMoveLine.getAccount().getLabel(),
creditMoveLine.getCredit().subtract(creditMoveLine.getAmountPaid()));
}
}
public void updatePartnerAccountingSituation(Reconcile reconcile) throws AxelorException {
List<Partner> partnerList = this.getPartners(reconcile);
if (partnerList != null && !partnerList.isEmpty()) {
Company company = reconcile.getDebitMoveLine().getMove().getCompany();
if (AccountingService.getUpdateCustomerAccount()) {
accountCustomerService.updatePartnerAccountingSituation(
partnerList, company, true, true, false);
} else {
accountCustomerService.flagPartners(partnerList, company);
}
}
}
public List<Partner> getPartners(Reconcile reconcile) {
List<Partner> partnerList = Lists.newArrayList();
Partner debitPartner = reconcile.getDebitMoveLine().getPartner();
Partner creditPartner = reconcile.getCreditMoveLine().getPartner();
if (debitPartner != null && creditPartner != null && debitPartner.equals(creditPartner)) {
partnerList.add(debitPartner);
} else if (debitPartner != null) {
partnerList.add(debitPartner);
} else if (creditPartner != null) {
partnerList.add(creditPartner);
}
return partnerList;
}
public void updateInvoiceCompanyInTaxTotalRemaining(Reconcile reconcile) throws AxelorException {
Invoice debitInvoice = reconcile.getDebitMoveLine().getMove().getInvoice();
Invoice creditInvoice = reconcile.getCreditMoveLine().getMove().getInvoice();
// Update amount remaining on invoice or refund
if (debitInvoice != null) {
debitInvoice.setCompanyInTaxTotalRemaining(
moveToolService.getInTaxTotalRemaining(debitInvoice));
}
if (creditInvoice != null) {
creditInvoice.setCompanyInTaxTotalRemaining(
moveToolService.getInTaxTotalRemaining(creditInvoice));
}
}
public void updateInvoicePayments(Reconcile reconcile) throws AxelorException {
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
Move debitMove = debitMoveLine.getMove();
Move creditMove = creditMoveLine.getMove();
Invoice debitInvoice = debitMove.getInvoice();
Invoice creditInvoice = creditMove.getInvoice();
BigDecimal amount = reconcile.getAmount();
if (debitInvoice != null
&& debitMoveLine.getAccount().getUseForPartnerBalance()
&& creditMoveLine.getAccount().getUseForPartnerBalance()) {
InvoicePayment debitInvoicePayment =
invoicePaymentCreateService.createInvoicePayment(debitInvoice, amount, creditMove);
debitInvoicePayment.setReconcile(reconcile);
}
if (creditInvoice != null
&& debitMoveLine.getAccount().getUseForPartnerBalance()
&& creditMoveLine.getAccount().getUseForPartnerBalance()) {
InvoicePayment creditInvoicePayment =
invoicePaymentCreateService.createInvoicePayment(creditInvoice, amount, debitMove);
creditInvoicePayment.setReconcile(reconcile);
}
}
protected void udpatePaymentTax(Reconcile reconcile) throws AxelorException {
Move debitMove = reconcile.getDebitMoveLine().getMove();
Move creditMove = reconcile.getCreditMoveLine().getMove();
Invoice debitInvoice = debitMove.getInvoice();
Invoice creditInvoice = creditMove.getInvoice();
if (debitInvoice != null && creditInvoice == null) {
moveLineService.generateTaxPaymentMoveLineList(
reconcile.getCreditMoveLine(), debitInvoice, reconcile);
}
if (creditInvoice != null && debitInvoice == null) {
moveLineService.generateTaxPaymentMoveLineList(
reconcile.getDebitMoveLine(), creditInvoice, reconcile);
}
}
/**
* Méthode permettant de lettrer une écriture au débit avec une écriture au crédit
*
* @param debitMoveLine
* @param creditMoveLine
* @throws AxelorException
*/
public Reconcile reconcile(
MoveLine debitMoveLine,
MoveLine creditMoveLine,
boolean canBeZeroBalanceOk,
boolean updateInvoicePayments)
throws AxelorException {
BigDecimal amount = debitMoveLine.getAmountRemaining().min(creditMoveLine.getAmountRemaining());
Reconcile reconcile =
this.createReconcile(debitMoveLine, creditMoveLine, amount, canBeZeroBalanceOk);
if (reconcile != null) {
this.confirmReconcile(reconcile, updateInvoicePayments);
return reconcile;
}
return null;
}
/**
* Permet de déréconcilier
*
* @param reconcile Une reconciliation
* @return L'etat de la réconciliation
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public void unreconcile(Reconcile reconcile) throws AxelorException {
log.debug("unreconcile : reconcile : {}", reconcile);
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
// Change the state
reconcile.setStatusSelect(ReconcileRepository.STATUS_CANCELED);
// Add the reconciled amount to the reconciled amount in the move line
creditMoveLine.setAmountPaid(creditMoveLine.getAmountPaid().subtract(reconcile.getAmount()));
debitMoveLine.setAmountPaid(debitMoveLine.getAmountPaid().subtract(reconcile.getAmount()));
reconcileRepository.save(reconcile);
// Update amount remaining on invoice or refund
this.updatePartnerAccountingSituation(reconcile);
this.updateInvoiceCompanyInTaxTotalRemaining(reconcile);
this.updateInvoicePaymentsCanceled(reconcile);
this.reverseTaxPaymentMoveLines(reconcile);
// Update reconcile group
Beans.get(ReconcileGroupService.class).remove(reconcile);
}
@Transactional(rollbackOn = {Exception.class})
public void unreconcile2(Reconcile reconcile) throws AxelorException {
log.debug("unreconcile : reconcile : {}", reconcile);
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
// Change the state
reconcile.setStatusSelect(ReconcileRepository.STATUS_CANCELED);
// Add the reconciled amount to the reconciled amount in the move line
creditMoveLine.setAmountPaid(creditMoveLine.getAmountPaid().subtract(reconcile.getAmount()));
debitMoveLine.setAmountPaid(debitMoveLine.getAmountPaid().subtract(reconcile.getAmount()));
reconcileRepository.save(reconcile);
// Update amount remaining on invoice or refund
this.updatePartnerAccountingSituation(reconcile);
this.updateInvoiceCompanyInTaxTotalRemaining(reconcile);
this.updateInvoicePaymentsCanceled(reconcile);
this.reverseTaxPaymentMoveLines(reconcile);
// Update reconcile group
// Beans.get(ReconcileGroupService.class).remove(reconcile);
}
protected void reverseTaxPaymentMoveLines(Reconcile reconcile) throws AxelorException {
Move debitMove = reconcile.getDebitMoveLine().getMove();
Move creditMove = reconcile.getCreditMoveLine().getMove();
Invoice debitInvoice = debitMove.getInvoice();
Invoice creditInvoice = creditMove.getInvoice();
if (debitInvoice == null) {
moveLineService.reverseTaxPaymentMoveLines(reconcile.getDebitMoveLine(), reconcile);
}
if (creditInvoice == null) {
moveLineService.reverseTaxPaymentMoveLines(reconcile.getCreditMoveLine(), reconcile);
}
}
public void updateInvoicePaymentsCanceled(Reconcile reconcile) throws AxelorException {
log.debug("updateInvoicePaymentsCanceled : reconcile : {}", reconcile);
List<InvoicePayment> invoicePaymentList =
Beans.get(InvoicePaymentRepository.class)
.all()
.filter("self.reconcile = ?1", reconcile)
.fetch();
for (InvoicePayment invoicePayment : invoicePaymentList) {
invoicePaymentCancelService.updateCancelStatus(invoicePayment);
}
}
/**
* Procédure permettant de gérer les écarts de règlement, check sur la case à cocher 'Peut être
* soldé' Alors nous utilisons la règle de gestion consitant à imputer l'écart sur un compte
* transitoire si le seuil est respecté
*
* @param reconcile Une reconciliation
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public void canBeZeroBalance(Reconcile reconcile) throws AxelorException {
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
BigDecimal debitAmountRemaining = debitMoveLine.getAmountRemaining();
log.debug("Montant à payer / à lettrer au débit : {}", debitAmountRemaining);
if (debitAmountRemaining.compareTo(BigDecimal.ZERO) > 0) {
Company company = reconcile.getDebitMoveLine().getMove().getCompany();
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
if (debitAmountRemaining.plus().compareTo(accountConfig.getThresholdDistanceFromRegulation())
< 0
|| reconcile.getMustBeZeroBalanceOk()) {
log.debug("Seuil respecté");
log.debug("Entrain de se cree");
MoveLine creditAdjustMoveLine =
moveAdjustementService.createAdjustmentCreditMove(debitMoveLine);
// Création de la réconciliation
Reconcile newReconcile =
this.createReconcile(debitMoveLine, creditAdjustMoveLine, debitAmountRemaining, false);
if (newReconcile != null) {
this.confirmReconcile(newReconcile, true);
reconcileRepository.save(newReconcile);
}
}
}
reconcile.setCanBeZeroBalanceOk(false);
log.debug("Fin de la gestion des écarts de règlement");
}
/**
* Solder le trop-perçu si il respect les règles de seuil
*
* @param creditMoveLine
* @param company
* @throws AxelorException
*/
public void balanceCredit(MoveLine creditMoveLine) throws AxelorException {
if (creditMoveLine != null) {
BigDecimal creditAmountRemaining = creditMoveLine.getAmountRemaining();
log.debug("Montant à payer / à lettrer au crédit : {}", creditAmountRemaining);
log.debug("creditMoveLine: {}", creditMoveLine.toString());
if (creditAmountRemaining.compareTo(BigDecimal.ZERO) > 0) {
AccountConfig accountConfig =
accountConfigService.getAccountConfig(creditMoveLine.getMove().getCompany());
if (creditAmountRemaining
.plus()
.compareTo(accountConfig.getThresholdDistanceFromRegulation())
< 0) {
log.debug("Seuil respecté");
MoveLine debitAdjustmentMoveLine =
moveAdjustementService.createAdjustmentDebitMove(creditMoveLine);
log.debug("/////////////// {}", creditAmountRemaining);
// Création de la réconciliation
Reconcile newReconcile =
this.createReconcile(
debitAdjustmentMoveLine, creditMoveLine, creditAmountRemaining, false);
if (newReconcile != null) {
this.confirmReconcile(newReconcile, true);
reconcileRepository.save(newReconcile);
}
}
}
}
}
public List<Reconcile> getReconciles(MoveLine moveLine) {
List<Reconcile> debitReconcileList = moveLine.getDebitReconcileList();
List<Reconcile> creditReconcileList = moveLine.getCreditReconcileList();
if (moveToolService.isDebitMoveLine(moveLine)) {
return debitReconcileList;
} else if (debitReconcileList != null && !creditReconcileList.isEmpty()) {
return creditReconcileList;
}
return Lists.newArrayList();
}
@Override
public Reconcile confirmPaymentVoucherReconcile(
Reconcile reconcile, boolean updateInvoicePayments) throws AxelorException {
this.reconcilePreconditions(reconcile);
MoveLine debitMoveLine = reconcile.getDebitMoveLine();
MoveLine creditMoveLine = reconcile.getCreditMoveLine();
// Add the reconciled amount to the reconciled amount in the move line
creditMoveLine.setAmountPaid(creditMoveLine.getAmountPaid().add(reconcile.getAmount()));
debitMoveLine.setAmountPaid(debitMoveLine.getAmountPaid().add(reconcile.getAmount()));
reconcile = reconcileRepository.save(reconcile);
reconcile.setStatusSelect(ReconcileRepository.STATUS_CONFIRMED);
if (reconcile.getCanBeZeroBalanceOk()) {
// Alors nous utilisons la règle de gestion consitant à imputer l'écart sur un compte
// transitoire si le seuil est respecté
canBeZeroBalance(reconcile);
}
reconcile.setReconciliationDate(LocalDate.now());
reconcileSequenceService.setSequence(reconcile);
this.updatePartnerAccountingSituation(reconcile);
this.updateInvoiceCompanyInTaxTotalRemaining(reconcile);
this.udpatePaymentTax(reconcile);
if (updateInvoicePayments) {
this.updateInvoicePayments(reconcile);
}
this.addToReconcileGroup(reconcile);
return reconcileRepository.save(reconcile);
}
}

View File

@ -0,0 +1,569 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reconcile;
import com.axelor.apps.account.db.Reimbursement;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.ReimbursementRepository;
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.move.MoveLineService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.BlockingRepository;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.db.repo.SequenceRepository;
import com.axelor.apps.base.service.BlockingService;
import com.axelor.apps.base.service.PartnerService;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.util.HashSet;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReimbursementExportService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected MoveService moveService;
protected MoveRepository moveRepo;
protected MoveLineService moveLineService;
protected ReconcileService reconcileService;
protected SequenceService sequenceService;
protected ReimbursementRepository reimbursementRepo;
protected AccountConfigService accountConfigService;
protected PartnerService partnerService;
protected PartnerRepository partnerRepository;
protected AppAccountService appAccountService;
@Inject
public ReimbursementExportService(
MoveService moveService,
MoveRepository moveRepo,
MoveLineService moveLineService,
ReconcileService reconcileService,
SequenceService sequenceService,
ReimbursementRepository reimbursementRepo,
AccountConfigService accountConfigService,
PartnerService partnerService,
AppAccountService appAccountService,
PartnerRepository partnerRepository) {
this.moveService = moveService;
this.moveRepo = moveRepo;
this.moveLineService = moveLineService;
this.reconcileService = reconcileService;
this.sequenceService = sequenceService;
this.reimbursementRepo = reimbursementRepo;
this.accountConfigService = accountConfigService;
this.partnerService = partnerService;
this.partnerRepository = partnerRepository;
this.appAccountService = appAccountService;
}
/** @param reimbursementExport */
public void fillMoveLineSet(
Reimbursement reimbursement, List<MoveLine> moveLineList, BigDecimal total) {
log.debug("In fillMoveLineSet");
log.debug("Nombre de trop-perçus trouvés : {}", moveLineList.size());
for (MoveLine moveLine : moveLineList) {
// On passe les lignes d'écriture (trop perçu) à l'état 'en cours de remboursement'
moveLine.setReimbursementStatusSelect(MoveLineRepository.REIMBURSEMENT_STATUS_REIMBURSING);
}
reimbursement.setMoveLineSet(new HashSet<MoveLine>());
reimbursement.getMoveLineSet().addAll(moveLineList);
log.debug("End fillMoveLineSet");
}
/**
* @param reimbursementExport
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public Reimbursement runCreateReimbursement(
List<MoveLine> moveLineList, Company company, Partner partner) throws AxelorException {
log.debug("In runReimbursementProcess");
BigDecimal total = this.getTotalAmountRemaining(moveLineList);
AccountConfig accountConfig = company.getAccountConfig();
// Seuil bas respecté et remboursement manuel autorisé
if (total.compareTo(accountConfig.getLowerThresholdReimbursement()) > 0) {
Reimbursement reimbursement = createReimbursement(partner, company);
fillMoveLineSet(reimbursement, moveLineList, total);
if (total.compareTo(accountConfig.getUpperThresholdReimbursement()) > 0
|| reimbursement.getBankDetails() == null) {
// Seuil haut dépassé
reimbursement.setStatusSelect(ReimbursementRepository.STATUS_TO_VALIDATE);
} else {
reimbursement.setStatusSelect(ReimbursementRepository.STATUS_VALIDATED);
}
reimbursement = reimbursementRepo.save(reimbursement);
return reimbursement;
}
log.debug("End runReimbursementProcess");
return null;
}
/**
* Fonction permettant de calculer le montant total restant à payer / à lettrer
*
* @param movelineList Une liste de ligne d'écriture
* @return Le montant total restant à payer / à lettrer
*/
public BigDecimal getTotalAmountRemaining(List<MoveLine> moveLineList) {
BigDecimal total = BigDecimal.ZERO;
for (MoveLine moveLine : moveLineList) {
total = total.add(moveLine.getAmountRemaining());
}
log.debug("Total Amount Remaining : {}", total);
return total;
}
/**
* Methode permettant de créer l'écriture de remboursement
*
* @param reimbursementExport Un objet d'export des prélèvements
* @throws AxelorException
*/
public void createReimbursementMove(Reimbursement reimbursement, Company company)
throws AxelorException {
reimbursement = reimbursementRepo.find(reimbursement.getId());
Partner partner = null;
Move newMove = null;
boolean first = true;
AccountConfig accountConfig = company.getAccountConfig();
if (reimbursement.getMoveLineSet() != null && !reimbursement.getMoveLineSet().isEmpty()) {
int seq = 1;
for (MoveLine moveLine : reimbursement.getMoveLineSet()) {
BigDecimal amountRemaining = moveLine.getAmountRemaining();
if (amountRemaining.compareTo(BigDecimal.ZERO) > 0) {
partner = moveLine.getPartner();
// On passe les lignes d'écriture (trop perçu) à l'état 'remboursé'
moveLine.setReimbursementStatusSelect(MoveLineRepository.REIMBURSEMENT_STATUS_REIMBURSED);
if (first) {
newMove =
moveService
.getMoveCreateService()
.createMove(
accountConfig.getReimbursementJournal(),
company,
null,
partner,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
first = false;
}
// Création d'une ligne au débit
MoveLine newDebitMoveLine =
moveLineService.createMoveLine(
newMove,
partner,
moveLine.getAccount(),
amountRemaining,
true,
appAccountService.getTodayDate(),
seq,
reimbursement.getRef(),
reimbursement.getDescription());
newMove.getMoveLineList().add(newDebitMoveLine);
if (reimbursement.getDescription() != null && !reimbursement.getDescription().isEmpty()) {
newDebitMoveLine.setDescription(reimbursement.getDescription());
}
seq++;
// Création de la réconciliation
Reconcile reconcile =
reconcileService.createReconcile(newDebitMoveLine, moveLine, amountRemaining, false);
if (reconcile != null) {
reconcileService.confirmReconcile(reconcile, true);
}
}
}
// Création de la ligne au crédit
MoveLine newCreditMoveLine =
moveLineService.createMoveLine(
newMove,
partner,
accountConfig.getReimbursementAccount(),
reimbursement.getAmountReimbursed(),
false,
appAccountService.getTodayDate(),
seq,
reimbursement.getRef(),
reimbursement.getDescription());
newMove.getMoveLineList().add(newCreditMoveLine);
if (reimbursement.getDescription() != null && !reimbursement.getDescription().isEmpty()) {
newCreditMoveLine.setDescription(reimbursement.getDescription());
}
moveService.getMoveValidateService().validate(newMove);
moveRepo.save(newMove);
}
}
/**
* Procédure permettant de tester la présence des champs et des séquences nécessaire aux
* remboursements.
*
* @param company Une société
* @throws AxelorException
*/
public void testCompanyField(Company company) throws AxelorException {
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
accountConfigService.getReimbursementAccount(accountConfig);
accountConfigService.getReimbursementJournal(accountConfig);
accountConfigService.getReimbursementExportFolderPath(accountConfig);
if (!sequenceService.hasSequence(SequenceRepository.REIMBOURSEMENT, company)) {
throw new AxelorException(
TraceBackRepository.CATEGORY_CONFIGURATION_ERROR,
I18n.get(IExceptionMessage.REIMBURSEMENT_1),
I18n.get(com.axelor.apps.base.exceptions.IExceptionMessage.EXCEPTION),
company.getName());
}
}
@Transactional(rollbackOn = {Exception.class})
public void reimburse(Reimbursement reimbursement, Company company) throws AxelorException {
reimbursement.setAmountReimbursed(reimbursement.getAmountToReimburse());
this.createReimbursementMove(reimbursement, company);
reimbursement.setStatusSelect(ReimbursementRepository.STATUS_REIMBURSED);
reimbursementRepo.save(reimbursement);
}
/**
* Méthode permettant de créer un remboursement
*
* @param partner Un tiers
* @param company Une société
* @param reimbursementExport Un export des remboursement
* @return Le remboursmeent créé
* @throws AxelorException
*/
public Reimbursement createReimbursement(Partner partner, Company company)
throws AxelorException {
Reimbursement reimbursement = new Reimbursement();
reimbursement.setPartner(partner);
reimbursement.setCompany(company);
BankDetails bankDetails = partnerService.getDefaultBankDetails(partner);
reimbursement.setBankDetails(bankDetails);
reimbursement.setRef(
sequenceService.getSequenceNumber(SequenceRepository.REIMBOURSEMENT, company));
return reimbursement;
}
/**
* Checks if the partner can be reimbursed
*
* @return true if partner can be reimbursed, false otherwise
*/
public boolean canBeReimbursed(Partner partner, Company company) {
return Beans.get(BlockingService.class)
.getBlocking(partner, company, BlockingRepository.REIMBURSEMENT_BLOCKING)
== null;
}
/**
* Procédure permettant de mettre à jour la liste des RIBs du tiers
*
* @param reimbursement Un remboursement
*/
@Transactional
public void updatePartnerCurrentRIB(Reimbursement reimbursement) {
BankDetails bankDetails = reimbursement.getBankDetails();
Partner partner = reimbursement.getPartner();
BankDetails defaultBankDetails = partnerService.getDefaultBankDetails(partner);
if (partner != null && bankDetails != null && !bankDetails.equals(defaultBankDetails)) {
bankDetails.setIsDefault(true);
defaultBankDetails.setIsDefault(false);
partner.addBankDetailsListItem(bankDetails);
partnerRepository.save(partner);
}
}
/*
/**
* Méthode permettant de créer un fichier xml de virement au format SEPA
* @param export
* @param datetime
* @param reimbursementList
* @throws AxelorException
* @throws DatatypeConfigurationException
* @throws JAXBException
* @throws IOException
public void exportSepa(Company company, ZonedDateTime datetime, List<Reimbursement> reimbursementList, BankDetails bankDetails) throws AxelorException, DatatypeConfigurationException, JAXBException, IOException {
String exportFolderPath = accountConfigService.getReimbursementExportFolderPath(accountConfigService.getAccountConfig(company));
if (exportFolderPath == null) {
throw new AxelorException(TraceBackRepository.CATEGORY_MISSING_FIELD, I18n.get(IExceptionMessage.REIMBURSEMENT_2), company.getName());
}
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance();
Date date = Date.from(datetime.toInstant());
BigDecimal ctrlSum = BigDecimal.ZERO;
int nbOfTxs = 0;
/**
* Création du documemnt XML en mémoire
-/
ObjectFactory factory = new ObjectFactory();
// Débit
// Paiement
ServiceLevel2Choice svcLvl = factory.createServiceLevel2Choice();
svcLvl.setCd(ServiceLevel1Code.SEPA);
PaymentTypeInformation1 pmtTpInf = factory.createPaymentTypeInformation1();
pmtTpInf.setSvcLvl(svcLvl);
// Payeur
PartyIdentification8 dbtr = factory.createPartyIdentification8();
dbtr.setNm(bankDetails.getOwnerName());
// IBAN
AccountIdentification3Choice iban = factory.createAccountIdentification3Choice();
iban.setIBAN(bankDetails.getIban());
CashAccount7 dbtrAcct = factory.createCashAccount7();
dbtrAcct.setId(iban);
// BIC
FinancialInstitutionIdentification5Choice finInstnId = factory.createFinancialInstitutionIdentification5Choice();
finInstnId.setBIC(bankDetails.getBank().getCode());
BranchAndFinancialInstitutionIdentification3 dbtrAgt = factory.createBranchAndFinancialInstitutionIdentification3();
dbtrAgt.setFinInstnId(finInstnId);
// Lot
PaymentInstructionInformation1 pmtInf = factory.createPaymentInstructionInformation1();
pmtInf.setPmtMtd(PaymentMethod3Code.TRF);
pmtInf.setPmtTpInf(pmtTpInf);
pmtInf.setReqdExctnDt(datatypeFactory.newXMLGregorianCalendar(dateFormat.format(date)));
pmtInf.setDbtr(dbtr);
pmtInf.setDbtrAcct(dbtrAcct);
pmtInf.setDbtrAgt(dbtrAgt);
// Crédit
CreditTransferTransactionInformation1 cdtTrfTxInf = null; PaymentIdentification1 pmtId = null;
AmountType2Choice amt = null; CurrencyAndAmount instdAmt = null;
PartyIdentification8 cbtr = null; CashAccount7 cbtrAcct = null;
BranchAndFinancialInstitutionIdentification3 cbtrAgt = null;
RemittanceInformation1 rmtInf = null;
for (Reimbursement reimbursement : reimbursementList){
reimbursement = reimbursementRepo.find(reimbursement.getId());
nbOfTxs++;
ctrlSum = ctrlSum.add(reimbursement.getAmountReimbursed());
bankDetails = reimbursement.getBankDetails();
// Paiement
pmtId = factory.createPaymentIdentification1();
pmtId.setEndToEndId(reimbursement.getRef());
// Montant
instdAmt = factory.createCurrencyAndAmount();
instdAmt.setCcy("EUR");
instdAmt.setValue(reimbursement.getAmountReimbursed());
amt = factory.createAmountType2Choice();
amt.setInstdAmt(instdAmt);
// Débiteur
cbtr = factory.createPartyIdentification8();
cbtr.setNm(bankDetails.getOwnerName());
// IBAN
iban = factory.createAccountIdentification3Choice();
iban.setIBAN(bankDetails.getIban());
cbtrAcct = factory.createCashAccount7();
cbtrAcct.setId(iban);
// BIC
finInstnId = factory.createFinancialInstitutionIdentification5Choice();
finInstnId.setBIC(bankDetails.getBank().getCode());
cbtrAgt = factory.createBranchAndFinancialInstitutionIdentification3();
cbtrAgt.setFinInstnId(finInstnId);
rmtInf = factory.createRemittanceInformation1();
rmtInf.getUstrd().add(reimbursement.getDescription());
// Transaction
cdtTrfTxInf = factory.createCreditTransferTransactionInformation1();
cdtTrfTxInf.setPmtId(pmtId);
cdtTrfTxInf.setAmt(amt);
cdtTrfTxInf.setCdtr(cbtr);
cdtTrfTxInf.setCdtrAcct(cbtrAcct);
cdtTrfTxInf.setCdtrAgt(cbtrAgt);
cdtTrfTxInf.setRmtInf(rmtInf);
pmtInf.getCdtTrfTxInf().add(cdtTrfTxInf);
}
// En-tête
dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
GroupHeader1 grpHdr = factory.createGroupHeader1();
grpHdr.setCreDtTm(datatypeFactory.newXMLGregorianCalendar(dateFormat.format(date)));
grpHdr.setNbOfTxs(Integer.toString(nbOfTxs));
grpHdr.setCtrlSum(ctrlSum);
grpHdr.setGrpg(Grouping1Code.MIXD);
grpHdr.setInitgPty(dbtr);
// Parent
Pain00100102 pain00100102 = factory.createPain00100102();
pain00100102.setGrpHdr(grpHdr);
pain00100102.getPmtInf().add(pmtInf);
// Document
Document xml = factory.createDocument();
xml.setPain00100102(pain00100102);
/**
* Création du documemnt XML physique
-/
Marschaller.marschalFile(factory.createDocument(xml), "com.axelor.apps.xsd.sepa",
exportFolderPath, String.format("%s.xml", dateFormat.format(date)));
}
*/
/**
* *********************** Remboursement lors d'une facture fin de cycle
* ********************************
*/
/**
* Procédure permettant de créer un remboursement si un trop perçu est généré à la facture fin de
* cycle
*
* @param partner Un tiers
* @param company Une société
* @param moveLine Un trop-perçu
* @throws AxelorException
*/
@SuppressWarnings("unchecked")
@Transactional(rollbackOn = {Exception.class})
public void createReimbursementInvoice(
Partner partner, Company company, List<? extends MoveLine> moveLineList)
throws AxelorException {
BigDecimal total = this.getTotalAmountRemaining((List<MoveLine>) moveLineList);
if (total.compareTo(BigDecimal.ZERO) > 0) {
this.testCompanyField(company);
Reimbursement reimbursement = this.createReimbursement(partner, company);
this.fillMoveLineSet(reimbursement, (List<MoveLine>) moveLineList, total);
if (total.compareTo(company.getAccountConfig().getUpperThresholdReimbursement()) > 0
|| reimbursement.getBankDetails() == null) {
// Seuil haut dépassé
reimbursement.setStatusSelect(ReimbursementRepository.STATUS_TO_VALIDATE);
} else {
// Seuil haut non dépassé
reimbursement.setStatusSelect(ReimbursementRepository.STATUS_VALIDATED);
}
reimbursementRepo.save(reimbursement);
}
}
/**
* Procédure permettant de créer un remboursement si un trop perçu est généré à la facture fin de
* cycle grand comptes
*
* @param invoice Une facture
* @throws AxelorException
*/
@Transactional(rollbackOn = {Exception.class})
public void createReimbursementInvoice(Invoice invoice) throws AxelorException {
Company company = invoice.getCompany();
Partner partner = invoice.getPartner();
MoveLineRepository moveLineRepo = Beans.get(MoveLineRepository.class);
// récupération des trop-perçus du tiers
List<? extends MoveLine> moveLineList =
moveLineRepo
.all()
.filter(
"self.account.useForPartnerBalance = 'true' "
+ "AND (self.move.statusSelect = ?1 OR self.move.statusSelect = ?2) AND self.amountRemaining > 0 AND self.credit > 0 AND self.partner = ?3 AND self.reimbursementStatusSelect = ?4 ",
MoveRepository.STATUS_VALIDATED,
MoveRepository.STATUS_DAYBOOK,
partner,
MoveLineRepository.REIMBURSEMENT_STATUS_NULL)
.fetch();
this.createReimbursementInvoice(partner, company, moveLineList);
}
}

View File

@ -0,0 +1,248 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.InterbankCodeLine;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.Reimbursement;
import com.axelor.apps.account.db.repo.MoveLineRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.ReimbursementRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
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.base.db.Company;
import com.axelor.apps.base.db.Partner;
import com.axelor.exception.AxelorException;
import com.axelor.exception.db.repo.TraceBackRepository;
import com.axelor.i18n.I18n;
import com.axelor.inject.Beans;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ReimbursementImportService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected MoveService moveService;
protected MoveRepository moveRepo;
protected MoveLineService moveLineService;
protected RejectImportService rejectImportService;
protected AccountConfigService accountConfigService;
protected ReimbursementRepository reimbursementRepo;
@Inject
public ReimbursementImportService(
MoveService moveService,
MoveRepository moveRepo,
MoveLineService moveLineService,
RejectImportService rejectImportService,
AccountConfigService accountConfigService,
ReimbursementRepository reimbursementRepo) {
this.moveService = moveService;
this.moveRepo = moveRepo;
this.moveLineService = moveLineService;
this.rejectImportService = rejectImportService;
this.accountConfigService = accountConfigService;
this.reimbursementRepo = reimbursementRepo;
}
@Transactional(rollbackOn = {Exception.class})
public void runReimbursementImport(Company company) throws AxelorException, IOException {
this.testCompanyField(company);
AccountConfig accountConfig = company.getAccountConfig();
this.createReimbursementRejectMove(
rejectImportService.getCFONBFile(
accountConfig.getReimbursementImportFolderPathCFONB(),
accountConfig.getTempReimbImportFolderPathCFONB(),
company,
0),
company);
}
public void createReimbursementRejectMove(List<String[]> rejectList, Company company)
throws AxelorException {
int seq = 1;
if (rejectList != null && !rejectList.isEmpty()) {
LocalDate rejectDate = rejectImportService.createRejectDate(rejectList.get(0)[0]);
Move move = this.createMoveReject(company, rejectDate);
for (String[] reject : rejectList) {
this.createReimbursementRejectMoveLine(reject, company, seq, move, rejectDate);
seq++;
}
if (move != null) {
// Création d'une ligne au débit
MoveLine debitMoveLine =
moveLineService.createMoveLine(
move,
null,
company.getAccountConfig().getReimbursementAccount(),
this.getTotalAmount(move),
true,
rejectDate,
seq,
null,
null);
move.getMoveLineList().add(debitMoveLine);
this.validateMove(move);
}
}
}
@Transactional(rollbackOn = {Exception.class})
public Reimbursement createReimbursementRejectMoveLine(
String[] reject, Company company, int seq, Move move, LocalDate rejectDate)
throws AxelorException {
String refReject = reject[1];
// String amountReject = reject[2];
InterbankCodeLine causeReject = rejectImportService.getInterbankCodeLine(reject[3], 0);
MoveLineRepository moveLineRepo = Beans.get(MoveLineRepository.class);
Reimbursement reimbursement =
reimbursementRepo
.all()
.filter("UPPER(self.ref) = ?1 AND self.company = ?2", refReject, company)
.fetchOne();
if (reimbursement == null) {
throw new AxelorException(
TraceBackRepository.CATEGORY_INCONSISTENCY,
I18n.get(IExceptionMessage.REIMBURSEMENT_3),
refReject,
company.getName());
}
Partner partner = reimbursement.getPartner();
BigDecimal amount = reimbursement.getAmountReimbursed();
// Création de la ligne au crédit
MoveLine creditMoveLine =
moveLineService.createMoveLine(
move,
partner,
company.getAccountConfig().getCustomerAccount(),
amount,
false,
rejectDate,
seq,
refReject,
null);
move.getMoveLineList().add(creditMoveLine);
moveLineRepo.save(creditMoveLine);
moveRepo.save(move);
creditMoveLine.setInterbankCodeLine(causeReject);
reimbursement.setRejectedOk(true);
reimbursement.setRejectDate(rejectDate);
reimbursement.setRejectMoveLine(creditMoveLine);
reimbursement.setInterbankCodeLine(causeReject);
reimbursementRepo.save(reimbursement);
return reimbursement;
}
@Transactional(rollbackOn = {Exception.class})
public Move createMoveReject(Company company, LocalDate date) throws AxelorException {
return moveRepo.save(
moveService
.getMoveCreateService()
.createMove(
company.getAccountConfig().getRejectJournal(),
company,
null,
null,
date,
null,
MoveRepository.TECHNICAL_ORIGIN_IMPORT));
}
public BigDecimal getTotalAmount(Move move) {
BigDecimal totalAmount = BigDecimal.ZERO;
for (MoveLine moveLine : move.getMoveLineList()) {
totalAmount = totalAmount.add(moveLine.getCredit());
}
return totalAmount;
}
@Transactional(rollbackOn = {Exception.class})
public MoveLine createOppositeRejectMoveLine(Move move, int seq, LocalDate rejectDate)
throws AxelorException {
// Création d'une ligne au débit
MoveLine debitMoveLine =
moveLineService.createMoveLine(
move,
null,
move.getCompany().getAccountConfig().getReimbursementAccount(),
this.getTotalAmount(move),
true,
rejectDate,
seq,
null,
null);
move.getMoveLineList().add(debitMoveLine);
moveRepo.save(move);
return debitMoveLine;
}
@Transactional(rollbackOn = {Exception.class})
public void validateMove(Move move) throws AxelorException {
moveService.getMoveValidateService().validate(move);
moveRepo.save(move);
}
@Transactional
public void deleteMove(Move move) {
moveRepo.remove(move);
}
/**
* Procédure permettant de tester la présence des champs et des séquences nécessaire aux rejets de
* remboursement.
*
* @param company Une société
* @throws AxelorException
*/
public void testCompanyField(Company company) throws AxelorException {
log.debug("Test de la société {}", company.getName());
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
accountConfigService.getReimbursementAccount(accountConfig);
accountConfigService.getRejectJournal(accountConfig);
accountConfigService.getReimbursementImportFolderPathCFONB(accountConfig);
accountConfigService.getTempReimbImportFolderPathCFONB(accountConfig);
}
}

View File

@ -0,0 +1,58 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.Reimbursement;
import com.axelor.apps.base.db.BankDetails;
import com.axelor.apps.base.db.Partner;
import com.axelor.apps.base.db.repo.PartnerRepository;
import com.axelor.apps.base.service.PartnerService;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
public class ReimbursementService {
protected PartnerRepository partnerRepository;
protected PartnerService partnerService;
@Inject
public ReimbursementService(PartnerRepository partnerRepository, PartnerService partnerService) {
this.partnerRepository = partnerRepository;
this.partnerService = partnerService;
}
/**
* Procédure permettant de mettre à jour la liste des RIBs du tiers
*
* @param reimbursement Un remboursement
*/
@Transactional
public void updatePartnerCurrentRIB(Reimbursement reimbursement) {
BankDetails bankDetails = reimbursement.getBankDetails();
Partner partner = reimbursement.getPartner();
BankDetails defaultBankDetails = partnerService.getDefaultBankDetails(partner);
if (bankDetails != null && partner != null && !bankDetails.equals(defaultBankDetails)) {
defaultBankDetails.setIsDefault(false);
bankDetails.setIsDefault(true);
partner.addBankDetailsListItem(bankDetails);
partnerRepository.save(partner);
}
}
}

View File

@ -0,0 +1,216 @@
/*
* 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.account.service;
import com.axelor.apps.account.db.InterbankCodeLine;
import com.axelor.apps.account.db.repo.InterbankCodeLineRepository;
import com.axelor.apps.account.service.app.AppAccountService;
import com.axelor.apps.account.service.bankorder.file.cfonb.CfonbImportService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.tool.file.FileTool;
import com.axelor.exception.AxelorException;
import com.google.common.io.Files;
import com.google.inject.Inject;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RejectImportService {
private final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected AppAccountService appAccountService;
protected CfonbImportService cfonbImportService;
protected InterbankCodeLineRepository interbankCodeLineRepo;
@Inject
public RejectImportService(
AppAccountService appAccountService,
CfonbImportService cfonbImportService,
InterbankCodeLineRepository interbankCodeLineRepo) {
this.appAccountService = appAccountService;
this.cfonbImportService = cfonbImportService;
this.interbankCodeLineRepo = interbankCodeLineRepo;
}
public String getDestFilename(String src, String dest) {
// chemin du fichier de destination :
log.debug("Chemin de destination : {}", dest);
String newDest = ((dest).split("\\."))[0];
String timeString = appAccountService.getTodayDateTime().toString();
timeString = timeString.replace("-", "");
timeString = timeString.replace(":", "");
timeString = timeString.replace(".", "");
timeString = timeString.replace("+", "");
newDest += "_" + timeString + ".";
if (dest.split("\\.").length == 2) {
newDest += dest.split("\\.")[1];
} else {
newDest += src.split("\\.")[1];
}
log.debug("Chemin de destination généré : {}", newDest);
return newDest;
}
public String getDestCFONBFile(String src, String temp) throws AxelorException, IOException {
String dest = this.getDestFilename(src, temp);
this.createFilePath(dest);
// copie du fichier d'import dans un repetoire temporaire
FileTool.copy(src, dest);
return dest;
}
/**
* @param src
* @param temp
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
* @throws AxelorException
* @throws IOException
*/
public List<String[]> getCFONBFile(String src, String temp, Company company, int operation)
throws AxelorException, IOException {
String dest = this.getDestCFONBFile(src, temp);
return cfonbImportService.importCFONB(dest, company, operation);
}
/**
* @param src
* @param temp
* @param company
* @param operation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement
* </ul>
*
* @return
* @throws AxelorException
* @throws IOException
*/
public Map<List<String[]>, String> getCFONBFileByLot(
String src, String temp, Company company, int operation) throws AxelorException, IOException {
String dest = this.getDestCFONBFile(src, temp);
return cfonbImportService.importCFONBByLot(dest, company, operation);
}
/**
* Fonction permettant de récupérer le motif de rejet/retour
*
* @param reasonCode Un code motifs de rejet/retour
* @param interbankCodeOperation Le type d'opération :
* <ul>
* <li>0 = Virement
* <li>1 = Prélèvement/TIP/Télérèglement
* <li>2 = Prélèvement SEPA
* <li>3 = LCR/BOR
* <li>4 = Cheque
* </ul>
*
* @return Un motif de rejet/retour
*/
public InterbankCodeLine getInterbankCodeLine(String reasonCode, int interbankCodeOperation) {
switch (interbankCodeOperation) {
case 0:
return interbankCodeLineRepo
.all()
.filter(
"self.code = ?1 AND self.interbankCode = ?2 AND self.transferCfonbOk = 'true'",
reasonCode,
appAccountService.getAppAccount().getTransferAndDirectDebitInterbankCode())
.fetchOne();
case 1:
return interbankCodeLineRepo
.all()
.filter(
"self.code = ?1 AND self.interbankCode = ?2 AND self.directDebitAndTipCfonbOk = 'true'",
reasonCode,
appAccountService.getAppAccount().getTransferAndDirectDebitInterbankCode())
.fetchOne();
case 2:
return interbankCodeLineRepo
.all()
.filter(
"self.code = ?1 AND self.interbankCode = ?2 AND self.directDebitSepaOk = 'true'",
reasonCode,
appAccountService.getAppAccount().getTransferAndDirectDebitInterbankCode())
.fetchOne();
case 3:
return interbankCodeLineRepo
.all()
.filter(
"self.code = ?1 AND self.interbankCode = ?2 AND self.lcrBorOk = 'true'",
reasonCode,
appAccountService.getAppAccount().getTransferAndDirectDebitInterbankCode())
.fetchOne();
case 4:
return interbankCodeLineRepo
.all()
.filter(
"self.code = ?1 AND self.interbankCode = ?2 AND self.chequeOk = 'true'",
reasonCode,
appAccountService.getAppAccount().getChequeInterbankCode())
.fetchOne();
default:
return null;
}
}
/**
* Méthode permettant de construire une date de rejet depuis le texte récupéré du fichier CFONB
*
* @param dateReject
* @return
*/
public LocalDate createRejectDate(String dateReject) {
return LocalDate.of(
Integer.parseInt(dateReject.substring(4, 6)) + 2000,
Integer.parseInt(dateReject.substring(2, 4)),
Integer.parseInt(dateReject.substring(0, 2)));
}
public void createFilePath(String path) throws IOException {
File file = new File(path);
Files.createParentDirs(file);
file.createNewFile();
}
}

View File

@ -0,0 +1,87 @@
/*
* Axelor Business Solutions
*
* Copyright (C) 2019 Axelor (<http://axelor.com>).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.axelor.apps.account.service;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.SubrogationRelease;
import com.axelor.apps.base.db.Company;
import com.axelor.exception.AxelorException;
import java.io.IOException;
import java.util.List;
public interface SubrogationReleaseService {
/**
* Retrieve ventilated invoices from factorized customers.
*
* @param company
* @return
*/
List<Invoice> retrieveInvoices(Company company);
/**
* Transmit a subrogation release (generate a sequence number and change status).
*
* @param subrogationRelease
* @throws AxelorException
*/
void transmitRelease(SubrogationRelease subrogationRelease) throws AxelorException;
/**
* Generate a PDF export.
*
* @param subrogationRelease
* @param name
* @return
* @throws AxelorException
*/
String printToPDF(SubrogationRelease subrogationRelease, String name) throws AxelorException;
/**
* Generate a CSV export.
*
* @param subrogationRelease
* @return
* @throws AxelorException
* @throws IOException
*/
String exportToCSV(SubrogationRelease subrogationRelease) throws AxelorException, IOException;
/**
* Enter a subrogation release in the accounts (create moves).
*
* @param subrogationRelease
* @throws AxelorException
*/
void enterReleaseInTheAccounts(SubrogationRelease subrogationRelease) throws AxelorException;
/**
* Clear the subrogation release
*
* @param subrogationRelease
*/
void clear(SubrogationRelease subrogationRelease);
/**
* Check if the all invoice of the subrogation release are completely cleared
*
* @param subrogationRelease
* @return
*/
boolean isSubrogationReleaseCompletelyPaid(SubrogationRelease subrogationRelease);
}

View File

@ -0,0 +1,304 @@
/*
* 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.account.service;
import com.axelor.apps.ReportFactory;
import com.axelor.apps.account.db.Account;
import com.axelor.apps.account.db.AccountConfig;
import com.axelor.apps.account.db.Invoice;
import com.axelor.apps.account.db.Journal;
import com.axelor.apps.account.db.Move;
import com.axelor.apps.account.db.MoveLine;
import com.axelor.apps.account.db.SubrogationRelease;
import com.axelor.apps.account.db.repo.InvoiceRepository;
import com.axelor.apps.account.db.repo.MoveRepository;
import com.axelor.apps.account.db.repo.SubrogationReleaseRepository;
import com.axelor.apps.account.exception.IExceptionMessage;
import com.axelor.apps.account.report.IReport;
import com.axelor.apps.account.service.config.AccountConfigService;
import com.axelor.apps.account.service.invoice.InvoiceToolService;
import com.axelor.apps.account.service.move.MoveService;
import com.axelor.apps.base.db.Company;
import com.axelor.apps.base.db.Sequence;
import com.axelor.apps.base.service.administration.SequenceService;
import com.axelor.apps.base.service.app.AppBaseService;
import com.axelor.apps.report.engine.ReportSettings;
import com.axelor.apps.tool.file.CsvTool;
import com.axelor.db.Query;
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.google.common.base.Strings;
import com.google.inject.Inject;
import com.google.inject.persist.Transactional;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class SubrogationReleaseServiceImpl implements SubrogationReleaseService {
protected AppBaseService appBaseService;
protected InvoiceRepository invoiceRepository;
@Inject
public SubrogationReleaseServiceImpl(
AppBaseService appBaseService, InvoiceRepository invoiceRepository) {
this.appBaseService = appBaseService;
this.invoiceRepository = invoiceRepository;
}
@Override
public List<Invoice> retrieveInvoices(Company company) {
Query<Invoice> query =
invoiceRepository
.all()
.filter(
"self.company = :company AND self.partner.factorizedCustomer = TRUE "
+ "AND self.statusSelect = :invoiceStatusVentilated "
+ "AND self.id not in ("
+ " select Invoices.id "
+ " from SubrogationRelease as SR "
+ " join SR.invoiceSet as Invoices "
+ " where SR.statusSelect in (:subrogationReleaseStatusTransmitted, :subrogationReleaseStatusAccounted, :subrogationReleaseStatusCleared))"
+ "AND ((self.amountRemaining > 0 AND self.hasPendingPayments = FALSE)"
+ " OR self.originalInvoice.id in ("
+ " select Invoices.id "
+ " from SubrogationRelease as SR "
+ " join SR.invoiceSet as Invoices "
+ " where SR.statusSelect in (:subrogationReleaseStatusTransmitted, :subrogationReleaseStatusAccounted, :subrogationReleaseStatusCleared)))")
.order("invoiceDate")
.order("dueDate")
.order("invoiceId");
query.bind("company", company);
query.bind("invoiceStatusVentilated", InvoiceRepository.STATUS_VENTILATED);
query.bind(
"subrogationReleaseStatusTransmitted", SubrogationReleaseRepository.STATUS_TRANSMITTED);
query.bind("subrogationReleaseStatusAccounted", SubrogationReleaseRepository.STATUS_ACCOUNTED);
query.bind("subrogationReleaseStatusCleared", SubrogationReleaseRepository.STATUS_CLEARED);
List<Invoice> invoiceList = query.fetch();
return invoiceList;
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void transmitRelease(SubrogationRelease subrogationRelease) throws AxelorException {
SequenceService sequenceService = Beans.get(SequenceService.class);
String sequenceNumber =
sequenceService.getSequenceNumber("subrogationRelease", subrogationRelease.getCompany());
if (Strings.isNullOrEmpty(sequenceNumber)) {
throw new AxelorException(
Sequence.class,
TraceBackRepository.CATEGORY_NO_VALUE,
I18n.get(IExceptionMessage.SUBROGATION_RELEASE_MISSING_SEQUENCE),
subrogationRelease.getCompany().getName());
}
subrogationRelease.setSequenceNumber(sequenceNumber);
subrogationRelease.setStatusSelect(SubrogationReleaseRepository.STATUS_TRANSMITTED);
subrogationRelease.setTransmissionDate(appBaseService.getTodayDate());
}
@Override
public String printToPDF(SubrogationRelease subrogationRelease, String name)
throws AxelorException {
ReportSettings reportSettings = ReportFactory.createReport(IReport.SUBROGATION_RELEASE, name);
reportSettings.addParam("SubrogationReleaseId", subrogationRelease.getId());
reportSettings.addParam("Locale", ReportSettings.getPrintingLocale(null));
reportSettings.addFormat("pdf");
reportSettings.toAttach(subrogationRelease);
reportSettings.generate();
return reportSettings.getFileLink();
}
@Override
public String exportToCSV(SubrogationRelease subrogationRelease)
throws AxelorException, IOException {
List<String[]> allMoveLineData = new ArrayList<>();
Comparator<Invoice> byInvoiceDate =
(i1, i2) -> i1.getInvoiceDate().compareTo(i2.getInvoiceDate());
Comparator<Invoice> byDueDate = (i1, i2) -> i1.getDueDate().compareTo(i2.getDueDate());
Comparator<Invoice> byInvoiceId = (i1, i2) -> i1.getInvoiceId().compareTo(i2.getInvoiceId());
List<Invoice> releaseDetails =
subrogationRelease
.getInvoiceSet()
.stream()
.sorted(byInvoiceDate.thenComparing(byDueDate).thenComparing(byInvoiceId))
.collect(Collectors.toList());
for (Invoice invoice : releaseDetails) {
String[] items = new String[6];
BigDecimal inTaxTotal = invoice.getInTaxTotal().abs();
if (InvoiceToolService.isOutPayment(invoice)) {
inTaxTotal = inTaxTotal.negate();
}
items[0] = invoice.getPartner().getPartnerSeq();
items[1] = invoice.getInvoiceId();
items[2] = invoice.getInvoiceDate().toString();
items[3] = invoice.getDueDate().toString();
items[4] = inTaxTotal.toString();
items[5] = invoice.getCurrency().getCode();
allMoveLineData.add(items);
}
AccountConfigService accountConfigService = Beans.get(AccountConfigService.class);
String filePath =
accountConfigService.getAccountConfig(subrogationRelease.getCompany()).getExportPath();
if (filePath == null) {
filePath = com.google.common.io.Files.createTempDir().getAbsolutePath();
} else {
new File(filePath).mkdirs();
}
String fileName =
String.format(
"%s %s.csv", I18n.get("Subrogation release"), subrogationRelease.getSequenceNumber());
Files.createDirectories(Paths.get(filePath));
Path path = Paths.get(filePath, fileName);
CsvTool.csvWriter(filePath, fileName, ';', null, allMoveLineData);
try (InputStream is = new FileInputStream(path.toFile())) {
Beans.get(MetaFiles.class).attach(is, fileName, subrogationRelease);
}
return path.toString();
}
@Override
@Transactional(rollbackOn = {Exception.class})
public void enterReleaseInTheAccounts(SubrogationRelease subrogationRelease)
throws AxelorException {
MoveService moveService = Beans.get(MoveService.class);
MoveRepository moveRepository = Beans.get(MoveRepository.class);
AccountConfigService accountConfigService = Beans.get(AccountConfigService.class);
AppBaseService appBaseService = Beans.get(AppBaseService.class);
Company company = subrogationRelease.getCompany();
AccountConfig accountConfig = accountConfigService.getAccountConfig(company);
Journal journal = accountConfigService.getAutoMiscOpeJournal(accountConfig);
Account factorCreditAccount = accountConfigService.getFactorCreditAccount(accountConfig);
Account factorDebitAccount = accountConfigService.getFactorDebitAccount(accountConfig);
if (subrogationRelease.getAccountingDate() == null) {
subrogationRelease.setAccountingDate(appBaseService.getTodayDate());
}
for (Invoice invoice : subrogationRelease.getInvoiceSet()) {
if (invoice.getCompanyInTaxTotalRemaining().compareTo(BigDecimal.ZERO) == 0) {
continue;
}
boolean isRefund = false;
if (invoice.getOperationTypeSelect() == InvoiceRepository.OPERATION_TYPE_CLIENT_REFUND) {
isRefund = true;
}
LocalDate date = subrogationRelease.getAccountingDate();
Move move =
moveService
.getMoveCreateService()
.createMove(
journal,
company,
company.getCurrency(),
invoice.getPartner(),
date,
null,
MoveRepository.TECHNICAL_ORIGIN_AUTOMATIC);
MoveLine creditMoveLine, debitMoveLine;
debitMoveLine =
moveService
.getMoveLineService()
.createMoveLine(
move,
invoice.getPartner(),
factorDebitAccount,
invoice.getCompanyInTaxTotalRemaining(),
!isRefund,
date,
null,
1,
subrogationRelease.getSequenceNumber(),
invoice.getInvoiceId());
creditMoveLine =
moveService
.getMoveLineService()
.createMoveLine(
move,
invoice.getPartner(),
factorCreditAccount,
invoice.getCompanyInTaxTotalRemaining(),
isRefund,
date,
null,
2,
subrogationRelease.getSequenceNumber(),
invoice.getInvoiceId());
move.addMoveLineListItem(debitMoveLine);
move.addMoveLineListItem(creditMoveLine);
move = moveRepository.save(move);
moveService.getMoveValidateService().validate(move);
invoice.setSubrogationRelease(subrogationRelease);
invoice.setSubrogationReleaseMove(move);
subrogationRelease.addMoveListItem(move);
}
subrogationRelease.setStatusSelect(SubrogationReleaseRepository.STATUS_ACCOUNTED);
}
@Override
@Transactional
public void clear(SubrogationRelease subrogationRelease) {
if (isSubrogationReleaseCompletelyPaid(subrogationRelease)) {
subrogationRelease.setStatusSelect(SubrogationReleaseRepository.STATUS_CLEARED);
}
}
@Override
public boolean isSubrogationReleaseCompletelyPaid(SubrogationRelease subrogationRelease) {
return subrogationRelease
.getInvoiceSet()
.stream()
.filter(p -> p.getAmountRemaining().compareTo(BigDecimal.ZERO) == 1)
.count()
== 0;
}
}

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