diff --git a/.gitignore b/.gitignore index 11335b7..e03074a 100644 --- a/.gitignore +++ b/.gitignore @@ -56,7 +56,7 @@ coverage.xml # Translations *.mo -*.pot +#*.pot # Django stuff: *.log diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e37e32e..0000000 --- a/LICENSE +++ /dev/null @@ -1,613 +0,0 @@ -GNU AFFERO GENERAL PUBLIC LICENSE - -Version 3, 19 November 2007 - -Copyright (C) 2007 Free Software Foundation, Inc. - -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 s ue 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. - - - -Copyright (C) - -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 . - -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 . diff --git a/README.md b/README.md deleted file mode 100644 index 70e1e63..0000000 --- a/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# addons_cm - -addons personalizados por Criptomart \ No newline at end of file diff --git a/barcode_generator_partner/README.rst b/barcode_generator_partner/README.rst new file mode 100644 index 0000000..0352349 --- /dev/null +++ b/barcode_generator_partner/README.rst @@ -0,0 +1,124 @@ +============================== +Generate Barcodes for Partners +============================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:0c984bdd1b103633bb285af4d69763047cc898ed9b6e3499c164a41d8e300f99 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--barcode-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-barcode/tree/12.0/barcodes_generator_partner + :alt: OCA/stock-logistics-barcode +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/stock-logistics-barcode-12-0/stock-logistics-barcode-12-0-barcodes_generator_partner + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-barcode&target_branch=12.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module expands Odoo functionality, allowing user to generate barcode +depending on a given barcode rule for Partners. + +For example, a typical pattern for partners is "042........." that means +that: + +* the EAN13 code will begin by '042' +* followed by 0 digits (named Barcode Base in this module) +* a 13 digit control + +With this module, it is possible to: + +* Assign a pattern (barcode.rule) to a res.partner + +* Define a Barcode base: + * manually, if the base of the barcode must be set by a user. (typically an + internal code defined in your company) + * automaticaly by a sequence, if you want to let Odoo to increment a + sequence. (typical case of a customer number incrementation) + +* Generate a barcode, based on the defined pattern and the barcode base + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +* To configure this module, see the 'Configuration' Section of the description of the module 'barcodes_generator_abstract' + +Usage +===== + +To use this module, you need to: + +* Go to a Customer/Contact form, Sales & Purchases Tab: + +1 for manual generation + * Set a Barcode Rule + * Set a Barcode Base + * click on the button 'Generate Barcode (Using Barcode Rule)' + +2 for automatic generation + * Set a Barcode Rule + * click on the button 'Generate Base (Using Sequence)' + * click on the button 'Generate Barcode (Using Barcode Rule)' + +.. image:: https://raw.githubusercontent.com/barcodes_generator_partner/static/description/res_partner_sequence_generation.png + :width: 1100px + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* GRAP +* La Louve + +Contributors +~~~~~~~~~~~~ + +* Sylvain LE GAL (https://twitter.com/legalsylvain) +* Dave Lasley +* Druidoo (https://druidoo.io) + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +This module is part of the `OCA/stock-logistics-barcode `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/barcode_generator_partner/__init__.py b/barcode_generator_partner/__init__.py new file mode 100644 index 0000000..83e553a --- /dev/null +++ b/barcode_generator_partner/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import models diff --git a/barcode_generator_partner/__manifest__.py b/barcode_generator_partner/__manifest__.py new file mode 100644 index 0000000..609cd7a --- /dev/null +++ b/barcode_generator_partner/__manifest__.py @@ -0,0 +1,27 @@ +# Copyright (C) 2014-Today GRAP (http://www.grap.coop) +# Copyright (C) 2016-Today La Louve (http://www.lalouve.net) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Generate Barcodes for Partners", + "summary": "Generate Barcodes for Partners", + "version": "16.0.1.0.1", + "category": "Tools", + "author": "GRAP," "La Louve," "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-barcode", + "license": "AGPL-3", + "depends": [ + "barcodes_generator_abstract", + "point_of_sale", + ], + "data": [ + "views/view_res_partner.xml", + ], + "demo": [ + "demo/ir_sequence.xml", + "demo/barcode_rule.xml", + "demo/res_partner.xml", + "demo/function.xml", + ], +} diff --git a/barcode_generator_partner/demo/barcode_rule.xml b/barcode_generator_partner/demo/barcode_rule.xml new file mode 100644 index 0000000..b3c7ee0 --- /dev/null +++ b/barcode_generator_partner/demo/barcode_rule.xml @@ -0,0 +1,25 @@ + + + + + + Partner Rule (Generated Barcode) + + client + 998 + ean13 + 042......... + + + + + + diff --git a/barcode_generator_partner/demo/function.xml b/barcode_generator_partner/demo/function.xml new file mode 100644 index 0000000..a2469da --- /dev/null +++ b/barcode_generator_partner/demo/function.xml @@ -0,0 +1,22 @@ + + + + + + + + + diff --git a/barcode_generator_partner/demo/ir_sequence.xml b/barcode_generator_partner/demo/ir_sequence.xml new file mode 100644 index 0000000..2aa10aa --- /dev/null +++ b/barcode_generator_partner/demo/ir_sequence.xml @@ -0,0 +1,16 @@ + + + + + + Partner Sequence (Generated Barcode) + 10 + 1 + + + diff --git a/barcode_generator_partner/demo/res_partner.xml b/barcode_generator_partner/demo/res_partner.xml new file mode 100644 index 0000000..147e9ff --- /dev/null +++ b/barcode_generator_partner/demo/res_partner.xml @@ -0,0 +1,15 @@ + + + + + + Partner with Generated Barcode + + + + diff --git a/barcode_generator_partner/i18n/barcodes_generator_partner.pot b/barcode_generator_partner/i18n/barcodes_generator_partner.pot new file mode 100644 index 0000000..2f1890a --- /dev/null +++ b/barcode_generator_partner/i18n/barcodes_generator_partner.pot @@ -0,0 +1,100 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * barcodes_generator_partner +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Alias" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_barcode_rule +msgid "Barcode Rule" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Client" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_res_partner +msgid "Contact" +msgstr "" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Barcode (Using Barcode Rule)" +msgstr "" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Base (Using Sequence)" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__generate_model +msgid "Generate Model" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,help:barcodes_generator_partner.field_barcode_rule__generate_model +msgid "If 'Generate Type' is set, mention the model related to this rule." +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Location" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Lot" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Package" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Partners" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Products" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Stock Location" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__type +msgid "Type" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Unit Product" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Weighted Product" +msgstr "" + diff --git a/barcode_generator_partner/i18n/es.po b/barcode_generator_partner/i18n/es.po new file mode 100644 index 0000000..b061309 --- /dev/null +++ b/barcode_generator_partner/i18n/es.po @@ -0,0 +1,110 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * barcodes_generator_partner +# +# Translators: +# enjolras , 2018 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-02-15 02:01+0000\n" +"PO-Revision-Date: 2018-02-15 02:01+0000\n" +"Last-Translator: enjolras , 2018\n" +"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Alias" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_barcode_rule +msgid "Barcode Rule" +msgstr "Regla de código de barras" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Client" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_res_partner +msgid "Contact" +msgstr "" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Barcode (Using Barcode Rule)" +msgstr "" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Base (Using Sequence)" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__generate_model +msgid "Generate Model" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,help:barcodes_generator_partner.field_barcode_rule__generate_model +msgid "If 'Generate Type' is set, mention the model related to this rule." +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Location" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Lot" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Package" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Partners" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Products" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Stock Location" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__type +msgid "Type" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Unit Product" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Weighted Product" +msgstr "" + +#~ msgid "Barcode Base" +#~ msgstr "Base de código de barras" + +#~ msgid "barcode.rule" +#~ msgstr "barcode.rule" diff --git a/barcode_generator_partner/i18n/es_ES.po b/barcode_generator_partner/i18n/es_ES.po new file mode 100644 index 0000000..1be7bea --- /dev/null +++ b/barcode_generator_partner/i18n/es_ES.po @@ -0,0 +1,128 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * barcodes_generator_partner +# +# Translators: +# OCA Transbot , 2017 +# Fernando Lara , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-05-02 00:27+0000\n" +"PO-Revision-Date: 2017-05-02 00:27+0000\n" +"Last-Translator: Fernando Lara , 2017\n" +"Language-Team: Spanish (Spain) (https://www.transifex.com/oca/teams/23907/" +"es_ES/)\n" +"Language: es_ES\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Alias" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_barcode_rule +msgid "Barcode Rule" +msgstr "Regla del codigo de barras" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Client" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_res_partner +msgid "Contact" +msgstr "" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Barcode (Using Barcode Rule)" +msgstr "" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Base (Using Sequence)" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__generate_model +#, fuzzy +msgid "Generate Model" +msgstr "Generar Tipo" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,help:barcodes_generator_partner.field_barcode_rule__generate_model +msgid "If 'Generate Type' is set, mention the model related to this rule." +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Location" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Lot" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Package" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Partners" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Products" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Stock Location" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__type +msgid "Type" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Unit Product" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Weighted Product" +msgstr "" + +#~ msgid "" +#~ "Allow to generate barcode, including a number (a base) in the final " +#~ "barcode.\n" +#~ " 'Base Set Manually' : User should set manually the value of the barcode " +#~ "base\n" +#~ " 'Base managed by Sequence': User will use a button to generate a new " +#~ "base. This base will be generated by a sequence" +#~ msgstr "" +#~ "Permitir generar código de barras, incluyendo un número (una base) en el " +#~ "código de barras final.'U+23CE'\n" +#~ "'Base Set Manually': El usuario debe establecer manualmente el valor del " +#~ "código de barras base'U+23CE'\n" +#~ "'Base administrada por Secuencia': El usuario utilizará un botón para " +#~ "generar una nueva base. Esta base será generada por una secuencia" + +#~ msgid "Barcode Base" +#~ msgstr "Base de código de barras" + +#~ msgid "barcode.rule" +#~ msgstr "regla.barra de codigos" diff --git a/barcode_generator_partner/i18n/fr.po b/barcode_generator_partner/i18n/fr.po new file mode 100644 index 0000000..246d6ca --- /dev/null +++ b/barcode_generator_partner/i18n/fr.po @@ -0,0 +1,127 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * barcodes_generator_partner +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-05-02 00:27+0000\n" +"PO-Revision-Date: 2017-05-02 00:27+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Alias" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_barcode_rule +msgid "Barcode Rule" +msgstr "Règle de code barre" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Client" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_res_partner +msgid "Contact" +msgstr "" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Barcode (Using Barcode Rule)" +msgstr "Générer un code barre (via règle de codes barre)" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Base (Using Sequence)" +msgstr "Générer une base (via une séquence)" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__generate_model +#, fuzzy +msgid "Generate Model" +msgstr "Type de génération" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,help:barcodes_generator_partner.field_barcode_rule__generate_model +msgid "If 'Generate Type' is set, mention the model related to this rule." +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Location" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Lot" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Package" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +#, fuzzy +msgid "Partners" +msgstr "Partenaire" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Products" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Stock Location" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__type +msgid "Type" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Unit Product" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Weighted Product" +msgstr "" + +#~ msgid "" +#~ "Allow to generate barcode, including a number (a base) in the final " +#~ "barcode.\n" +#~ " 'Base Set Manually' : User should set manually the value of the barcode " +#~ "base\n" +#~ " 'Base managed by Sequence': User will use a button to generate a new " +#~ "base. This base will be generated by a sequence" +#~ msgstr "" +#~ "Autorise à générer des codes barre en incluant un numéro (base du code " +#~ "barre) dans le code barre final.\n" +#~ " 'Base indiquée manuellement' : L'utilisateur devra indiquer manuellement " +#~ "la base du barcode\n" +#~ " 'Base gérée via une séquence': L'utilisateur devra utiliser un boutton " +#~ "pour générer une nouvelle base. Cette base sera générée par une séquence" + +#~ msgid "Barcode Base" +#~ msgstr "Base du code Barre" + +#~ msgid "barcode.rule" +#~ msgstr "barcode.rule" diff --git a/barcode_generator_partner/i18n/hr.po b/barcode_generator_partner/i18n/hr.po new file mode 100644 index 0000000..a3884f4 --- /dev/null +++ b/barcode_generator_partner/i18n/hr.po @@ -0,0 +1,128 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * barcodes_generator_partner +# +# Translators: +# Bole , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-02-15 02:01+0000\n" +"PO-Revision-Date: 2018-02-15 02:01+0000\n" +"Last-Translator: Bole , 2017\n" +"Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Alias" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_barcode_rule +msgid "Barcode Rule" +msgstr "Barkod pravilo" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Client" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_res_partner +msgid "Contact" +msgstr "" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Barcode (Using Barcode Rule)" +msgstr "Generiraj barkod (koristeći pravilo)" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Base (Using Sequence)" +msgstr "Generiraj osnovno ( koristi br.krug)" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__generate_model +#, fuzzy +msgid "Generate Model" +msgstr "Tip generatora" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,help:barcodes_generator_partner.field_barcode_rule__generate_model +msgid "If 'Generate Type' is set, mention the model related to this rule." +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Location" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Lot" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Package" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +#, fuzzy +msgid "Partners" +msgstr "Partner" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Products" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Stock Location" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__type +msgid "Type" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Unit Product" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Weighted Product" +msgstr "" + +#~ msgid "" +#~ "Allow to generate barcode, including a number (a base) in the final " +#~ "barcode.\n" +#~ " 'Base Set Manually' : User should set manually the value of the barcode " +#~ "base\n" +#~ " 'Base managed by Sequence': User will use a button to generate a new " +#~ "base. This base will be generated by a sequence" +#~ msgstr "" +#~ "Omogućuje generiranje barkodova, uključujući broj(osnova) u finalnom " +#~ "barkodu.\n" +#~ "'Osnova postavljena ručno' : korisnik treba ručno postaviti vrijednost " +#~ "osnovice barkoda.\n" +#~ "'Osnova prema sekvenci' : korisnik će koristiti guzmb za generirnje nove " +#~ "osnove. Ta osnova će biti generirana iz sekvence." + +#~ msgid "Barcode Base" +#~ msgstr "Osnova barkodova" + +#~ msgid "barcode.rule" +#~ msgstr "barcode.rule" diff --git a/barcode_generator_partner/i18n/nl_NL.po b/barcode_generator_partner/i18n/nl_NL.po new file mode 100644 index 0000000..5496f50 --- /dev/null +++ b/barcode_generator_partner/i18n/nl_NL.po @@ -0,0 +1,108 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * barcodes_generator_partner +# +# Translators: +# Peter Hageman , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-07-07 15:18+0000\n" +"PO-Revision-Date: 2017-07-07 15:18+0000\n" +"Last-Translator: Peter Hageman , 2017\n" +"Language-Team: Dutch (Netherlands) (https://www.transifex.com/oca/" +"teams/23907/nl_NL/)\n" +"Language: nl_NL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Alias" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_barcode_rule +msgid "Barcode Rule" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Client" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model,name:barcodes_generator_partner.model_res_partner +msgid "Contact" +msgstr "" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Barcode (Using Barcode Rule)" +msgstr "" + +#. module: barcodes_generator_partner +#: model_terms:ir.ui.view,arch_db:barcodes_generator_partner.view_res_partner_form +msgid "Generate Base (Using Sequence)" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__generate_model +msgid "Generate Model" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,help:barcodes_generator_partner.field_barcode_rule__generate_model +msgid "If 'Generate Type' is set, mention the model related to this rule." +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Location" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Lot" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Package" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Partners" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Products" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,generate_model:0 +msgid "Stock Location" +msgstr "" + +#. module: barcodes_generator_partner +#: model:ir.model.fields,field_description:barcodes_generator_partner.field_barcode_rule__type +msgid "Type" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Unit Product" +msgstr "" + +#. module: barcodes_generator_partner +#: selection:barcode.rule,type:0 +msgid "Weighted Product" +msgstr "" + +#~ msgid "barcode.rule" +#~ msgstr "barcode.rule" diff --git a/barcode_generator_partner/models/__init__.py b/barcode_generator_partner/models/__init__.py new file mode 100644 index 0000000..d04ceba --- /dev/null +++ b/barcode_generator_partner/models/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import barcode_rule +from . import res_partner diff --git a/barcode_generator_partner/models/barcode_rule.py b/barcode_generator_partner/models/barcode_rule.py new file mode 100644 index 0000000..5442fb5 --- /dev/null +++ b/barcode_generator_partner/models/barcode_rule.py @@ -0,0 +1,12 @@ +# Copyright (C) 2014-Today GRAP (http://www.grap.coop) +# Copyright (C) 2016-Today La Louve (http://www.lalouve.net) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class BarcodeRule(models.Model): + _inherit = "barcode.rule" + + generate_model = fields.Selection(selection_add=[("res.partner", "Partners")]) diff --git a/barcode_generator_partner/models/res_partner.py b/barcode_generator_partner/models/res_partner.py new file mode 100644 index 0000000..63490f2 --- /dev/null +++ b/barcode_generator_partner/models/res_partner.py @@ -0,0 +1,11 @@ +# Copyright (C) 2014-Today GRAP (http://www.grap.coop) +# Copyright (C) 2016-Today La Louve (http://www.lalouve.net) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models + + +class ResPartner(models.Model): + _name = "res.partner" + _inherit = ["res.partner", "barcode.generate.mixin"] diff --git a/barcode_generator_partner/readme/CONFIGURE.rst b/barcode_generator_partner/readme/CONFIGURE.rst new file mode 100644 index 0000000..f49c227 --- /dev/null +++ b/barcode_generator_partner/readme/CONFIGURE.rst @@ -0,0 +1 @@ +* To configure this module, see the 'Configuration' Section of the description of the module 'barcodes_generator_abstract' diff --git a/barcode_generator_partner/readme/CONTRIBUTORS.rst b/barcode_generator_partner/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000..26d1341 --- /dev/null +++ b/barcode_generator_partner/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* Sylvain LE GAL (https://twitter.com/legalsylvain) +* Dave Lasley +* Druidoo (https://druidoo.io) +* Armand POLMARD (https://github.com/ArPol-developpement) diff --git a/barcode_generator_partner/readme/DESCRIPTION.rst b/barcode_generator_partner/readme/DESCRIPTION.rst new file mode 100644 index 0000000..12c9c26 --- /dev/null +++ b/barcode_generator_partner/readme/DESCRIPTION.rst @@ -0,0 +1,21 @@ +This module expands Odoo functionality, allowing user to generate barcode +depending on a given barcode rule for Partners. + +For example, a typical pattern for partners is "042........." that means +that: + +* the EAN13 code will begin by '042' +* followed by 0 digits (named Barcode Base in this module) +* a 13 digit control + +With this module, it is possible to: + +* Assign a pattern (barcode.rule) to a res.partner + +* Define a Barcode base: + * manually, if the base of the barcode must be set by a user. (typically an + internal code defined in your company) + * automaticaly by a sequence, if you want to let Odoo to increment a + sequence. (typical case of a customer number incrementation) + +* Generate a barcode, based on the defined pattern and the barcode base diff --git a/barcode_generator_partner/readme/USAGE.rst b/barcode_generator_partner/readme/USAGE.rst new file mode 100644 index 0000000..952c993 --- /dev/null +++ b/barcode_generator_partner/readme/USAGE.rst @@ -0,0 +1,16 @@ +To use this module, you need to: + +* Go to a Customer/Contact form, Sales & Purchases Tab: + +1 for manual generation + * Set a Barcode Rule + * Set a Barcode Base + * click on the button 'Generate Barcode (Using Barcode Rule)' + +2 for automatic generation + * Set a Barcode Rule + * click on the button 'Generate Base (Using Sequence)' + * click on the button 'Generate Barcode (Using Barcode Rule)' + +.. image:: /barcodes_generator_partner/static/description/res_partner_sequence_generation.png + :width: 1100px diff --git a/barcode_generator_partner/static/description/icon.png b/barcode_generator_partner/static/description/icon.png new file mode 100644 index 0000000..00f4e89 Binary files /dev/null and b/barcode_generator_partner/static/description/icon.png differ diff --git a/barcode_generator_partner/static/description/index.html b/barcode_generator_partner/static/description/index.html new file mode 100644 index 0000000..3b08781 --- /dev/null +++ b/barcode_generator_partner/static/description/index.html @@ -0,0 +1,480 @@ + + + + + + +Generate Barcodes for Partners + + + +
+

Generate Barcodes for Partners

+ + +

Beta License: AGPL-3 OCA/stock-logistics-barcode Translate me on Weblate Try me on Runboat

+

This module expands Odoo functionality, allowing user to generate barcode +depending on a given barcode rule for Partners.

+

For example, a typical pattern for partners is “042………” that means +that:

+
    +
  • the EAN13 code will begin by ‘042’
  • +
  • followed by 0 digits (named Barcode Base in this module)
  • +
  • a 13 digit control
  • +
+

With this module, it is possible to:

+
    +
  • Assign a pattern (barcode.rule) to a res.partner
  • +
  • +
    Define a Barcode base:
    +
      +
    • manually, if the base of the barcode must be set by a user. (typically an +internal code defined in your company)
    • +
    • automaticaly by a sequence, if you want to let Odoo to increment a +sequence. (typical case of a customer number incrementation)
    • +
    +
    +
    +
  • +
  • Generate a barcode, based on the defined pattern and the barcode base
  • +
+

Table of contents

+ +
+

Configuration

+
    +
  • To configure this module, see the ‘Configuration’ Section of the description of the module ‘barcodes_generator_abstract’
  • +
+
+
+

Usage

+

To use this module, you need to:

+
    +
  • Go to a Customer/Contact form, Sales & Purchases Tab:
  • +
+
+
1 for manual generation
+
    +
  • Set a Barcode Rule
  • +
  • Set a Barcode Base
  • +
  • click on the button ‘Generate Barcode (Using Barcode Rule)’
  • +
+
+
2 for automatic generation
+
    +
  • Set a Barcode Rule
  • +
  • click on the button ‘Generate Base (Using Sequence)’
  • +
  • click on the button ‘Generate Barcode (Using Barcode Rule)’
  • +
+
+
+https://raw.githubusercontent.com/barcodes_generator_partner/static/description/res_partner_sequence_generation.png +
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • GRAP
  • +
  • La Louve
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/stock-logistics-barcode project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/barcode_generator_partner/static/description/res_partner_sequence_generation.png b/barcode_generator_partner/static/description/res_partner_sequence_generation.png new file mode 100644 index 0000000..4b16e35 Binary files /dev/null and b/barcode_generator_partner/static/description/res_partner_sequence_generation.png differ diff --git a/barcode_generator_partner/tests/__init__.py b/barcode_generator_partner/tests/__init__.py new file mode 100644 index 0000000..22d1a55 --- /dev/null +++ b/barcode_generator_partner/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import test_barcodes_generator_partner diff --git a/barcode_generator_partner/tests/test_barcodes_generator_partner.py b/barcode_generator_partner/tests/test_barcodes_generator_partner.py new file mode 100644 index 0000000..2c72523 --- /dev/null +++ b/barcode_generator_partner/tests/test_barcodes_generator_partner.py @@ -0,0 +1,33 @@ +# Copyright (C) 2016-Today GRAP (http://www.grap.coop) +# Copyright (C) 2016-Today La Louve (http://www.lalouve.net) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests.common import TransactionCase + + +class Tests(TransactionCase): + """Tests for 'Barcodes Generate""" + + def setUp(self): + super().setUp() + self.partner_obj = self.env["res.partner"] + + # Test Section + def test_01_sequence_generation_partner(self): + self.partner = self.partner_obj.browse( + self.ref("barcodes_generator_partner.res_partner_barcode") + ) + self.partner.generate_barcode() + self.assertEqual( + self.partner.barcode_base, + 1, + "Incorrect base Generation (by sequence) for Partner.", + ) + self.assertEqual( + self.partner.barcode, + "0420000000013", + "Barcode Generation (by sequence) for Partner." + "Incorrect EAN13 Generated. Pattern : %s - Base : %s" + % (self.partner.barcode_rule_id.pattern, self.partner.barcode_base), + ) diff --git a/barcode_generator_partner/views/view_res_partner.xml b/barcode_generator_partner/views/view_res_partner.xml new file mode 100644 index 0000000..4050f09 --- /dev/null +++ b/barcode_generator_partner/views/view_res_partner.xml @@ -0,0 +1,63 @@ + + + + + + res.partner + + + + + + + - -
- Request for Quotation - Purchase Order -

- -

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - -
- -
-
- -
- diff --git a/purchase_collective/views/sale_order.xml b/purchase_collective/views/sale_order.xml deleted file mode 100644 index a5a0b1c..0000000 --- a/purchase_collective/views/sale_order.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - sale order collective purchase extension - sale.order - - - - - - - - - - - - diff --git a/purchase_order_product_recommendation_supermarket/README.rst b/purchase_order_product_recommendation_supermarket/README.rst new file mode 100644 index 0000000..4ec0488 --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/README.rst @@ -0,0 +1,30 @@ +================================================= +Purchase Order Product Recommendation Supermarket +================================================= + +Extends “purchase_order_product_recommendation” to add functionalities for food shops + +Purpose +======= + +#. Allows to indicate the number of days for which the quantity calculation will be made. If this field is defined, the quantity ordered will be calculated as “quantity/day * no. of days to cover”. +#. Allows to define the quantities according to the packaging of the products. +#. New check field “Do not take into account days with 0 stock”. In the case of activating this check, the desired behavior would be to disregard in the calculation of daily sales the days when the stock of that product was at 0 or less than 0. +#. New column indicating the scraps of the product in the period under analysis + +Configuration +============= + +To configure this module, you need to: + +#. Mark the desired settings in the wizard + +Usage +===== + +To use this module, you need to: + +#. Go to the purchase order form view. +#. Click on the "Recommend Products" button. +#. In the wizard that appears, configure the desired settings. +#. Click "Confirm" to generate the product recommendations. diff --git a/purchase_order_product_recommendation_supermarket/__init__.py b/purchase_order_product_recommendation_supermarket/__init__.py new file mode 100644 index 0000000..aee8895 --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/purchase_order_product_recommendation_supermarket/__manifest__.py b/purchase_order_product_recommendation_supermarket/__manifest__.py new file mode 100644 index 0000000..880934c --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/__manifest__.py @@ -0,0 +1,26 @@ +# Copyright 2025 Criptomart +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Purchase Order Product Recommendation Supermarket", + "summary": """Extends “purchase_order_product_recommendation” to add functionalities for food shops""", + "version": "16.0.0.1.0", + "license": "AGPL-3", + "author": "Criptomart", + "website": "https://criptomart.net", + "depends": ["purchase_order_product_recommendation"], + "data": [ + "security/ir.model.access.csv", + "wizards/purchase_order_recommendation.xml", + "views/product_template_view.xml", + "views/product_stock_out_period_menu.xml", + "data/stock_out_cron.xml", + ], + "assets": { + "web.assets_backend": [ + "purchase_order_product_recommendation_supermarket/static/src/scss/sticky_recommendation.scss", + # "purchase_order_product_recommendation_supermarket/static/src/js/sticky_recommendation.js", + ], + }, + "demo": [], +} diff --git a/purchase_order_product_recommendation_supermarket/data/stock_out_cron.xml b/purchase_order_product_recommendation_supermarket/data/stock_out_cron.xml new file mode 100644 index 0000000..72843b6 --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/data/stock_out_cron.xml @@ -0,0 +1,15 @@ + + + + Update Stock-out Periods + + code + model.cron_update_stock_out_periods() + + True + 1 + days + -1 + False + + diff --git a/purchase_order_product_recommendation_supermarket/i18n/es.po b/purchase_order_product_recommendation_supermarket/i18n/es.po new file mode 100644 index 0000000..7a1005f --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/i18n/es.po @@ -0,0 +1,546 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_order_product_recommendation_supermarket +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-10-02 11:22+0000\n" +"PO-Revision-Date: 2025-10-02 11:22+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_template_form_po_min_suggest +msgid "Stock-out Periods" +msgstr "Periodos sin stock" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_template__stock_out_period_ids +msgid "Stock-out Periods" +msgstr "Periodos sin stock" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__start_date +msgid "Start Date" +msgstr "Fecha inicio" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__end_date +msgid "End Date" +msgstr "Fecha fin" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__start_date +msgid "First calendar day when the product had zero stock in this period." +msgstr "Primer día (calendario) en el que el producto estuvo sin stock en este periodo." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__end_date +msgid "Last calendar day (inclusive) the product remained without stock in this period." +msgstr "Último día (incluido) en el que el producto siguió sin stock en este periodo." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__is_open +msgid "Open" +msgstr "Abierto" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__days_out +msgid "Days without Stock" +msgstr "Días sin stock" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__product_tmpl_id +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__product_tmpl_id +msgid "Product template this stock-out period belongs to." +msgstr "Plantilla de producto a la que pertenece este periodo sin stock." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__is_open +msgid "Indicates the period is still ongoing (stock not yet restored)." +msgstr "Indica que el periodo sigue en curso (el stock todavía no se ha recuperado)." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__days_out +msgid "Total number of calendar days (inclusive) without stock for this period." +msgstr "Número total de días naturales (incluidos) sin stock durante este periodo." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__include_previous_period +msgid "Include previous period stats" +msgstr "Incluir estadísticas del periodo previo" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__include_previous_period +msgid "If disabled, the previous period (same number of days immediately preceding) is NOT queried. This saves a read_group on stock move lines and skips zero-stock day analysis for that window." +msgstr "Si se desactiva, no se consulta el periodo previo (mismo número de días inmediatamente anteriores). Ahorra tiempo en el cálculo al no consultar movimientos de stock y omite el análisis de días sin stock para esa ventana de tiempo." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_template__po_min_suggest_if_forecast_le_zero +msgid "Suggest minimum purchase when forecast <= 0" +msgstr "Sugerir compra mínima cuando el stock previsto <= 0" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_template__po_min_suggest_if_forecast_le_zero +msgid "If enabled, the purchase recommendation wizard will always propose at least 1 unit (or 1 full package when ordering by packages) when the forecasted stock is less or equal to 0." +msgstr "Si se activa, el asistente de recomendación de compras propondrá siempre al menos 1 unidad (o 1 paquete completo al pedir por paquetes) cuando el stock previsto sea menor o igual que 0." + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_template_form_po_min_suggest +msgid "Purchase Recommendation" +msgstr "Recomendación de compra" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_avg_delivered_prev +msgid "Average daily consumption during the previous period" +msgstr "Media de consumo por día del periodo anterior" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_avg_delivered +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_avg_delivered +msgid "Average daily consumption during the selected period." +msgstr "Media de ventas por día." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__avg_days_between_orders +msgid "Average days between orders" +msgstr "Promedio de días entre pedidos" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__avg_days_between_orders +msgid "Average number of days between orders for this vendor." +msgstr "Número medio de días entre pedidos para este proveedor." + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Avg Prev Period" +msgstr "Ventas/día previas" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Calculate" +msgstr "Calcular" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__currency_id +msgid "Currency" +msgstr "Moneda" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_available +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_available +msgid "Current stock available in the warehouse." +msgstr "Cantidad de productos en stock" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__date_last_order +msgid "Date of last order" +msgstr "Fecha Último Pedido" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__date_last_order +msgid "Date of the last order received from the vendor." +msgstr "Fecha del último pedido recibido del proveedor." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__days_without_stock +msgid "Days without stock" +msgstr "Días sin stock" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_virtual_available +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_virtual_available +msgid "Forecasted stock, considering incoming and outgoing stock." +msgstr "" +"Cantidad de productos en stock + Cantidad de producto por venir (pedidos " +"confirmados)" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_form +msgid "Stock-out Period" +msgstr "Periodo sin stock" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_tree +#: model:ir.actions.act_window,name:purchase_order_product_recommendation_supermarket.action_product_stock_out_period +#: model:ir.ui.menu,name:purchase_order_product_recommendation_supermarket.menu_product_stock_out_period +msgid "Stock-out Periods" +msgstr "Periodos sin stock" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_search +msgid "Open" +msgstr "Abierto" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_search +msgid "Closed" +msgstr "Cerrado" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_search +msgid "Search Stock-out Periods" +msgstr "Buscar periodos sin stock" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_search +msgid "Open State" +msgstr "Estado (abierto)" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_search +msgid "Product" +msgstr "Producto" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.actions.act_window,help:purchase_order_product_recommendation_supermarket.action_product_stock_out_period +msgid "List of computed periods where a product template had zero stock. Open periods are still ongoing." +msgstr "Listado de periodos calculados en los que una plantilla de producto estuvo sin stock. Los periodos abiertos siguen en curso." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__ignore_zero_stock_days +msgid "" +"If enabled, days when the product stock was 0 or less will not be considered" +" in the daily sales calculation." +msgstr "" +"Si se activa, los días en los que el stock era 0 o negativo no se tendrán en" +" cuenta en el cálculo de las ventas diarias. Esto significa que hará una " +"estimación más realista y al alza." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__ignore_zero_stock_days +msgid "Ignore days with zero stock" +msgstr "Ignorar días sin stock" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_days +msgid "" +"Indicate for how many days the new order should cover the stock. If not set," +" the default module behavior is kept." +msgstr "" +"Indica durante cuantos días el nuevo pedido debe cubrir el stock. Si no se " +"rellena este campo las recomendaciones mostradas se calcularán para cubrir " +"un periodo equivalente al mostrado en días analizados." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_by_packages +msgid "Indicates if the order should be made by packages." +msgstr "" +"Indica si el pedido debe ajustarse al contenido por paquete. El contenido " +"por paquete se configura en la pestaña inventario de la ficha de producto." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_code +msgid "Internal reference of the product to be purchased from the vendor." +msgstr "Referencia interna" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__last_order_total_amount +msgid "Last Order total amount" +msgstr "Importe último pedido" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__last_order_total_amount +msgid "Last Order total amount without taxes" +msgstr "Importe del último pedido, sin IVA." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_name +msgid "Name of the product to be purchased from the vendor." +msgstr "Nombre interno del producto" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__days_without_stock +msgid "" +"Number of days in the selected period in which the on-hand quantity was 0." +msgstr "" +"Número de días en el periodo seleccionado en los cuales la Ctd a mano era 0." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__stock_duration +msgid "Number of days the current stock should last." +msgstr "Número de días que nos debería durar el stock actual." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__line_amount +msgid "Number of recommendations" +msgstr "Número de recomendaciones" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_scrapped +msgid "Number of units recorded as scrap during the period" +msgstr "Nº de unidades registradas como mermas durante el periodo" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_by_packages +msgid "Order by packages" +msgstr "Pedir por paquetes" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_days +msgid "Order coverage (days)" +msgstr "Días a cubrir" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__subtotal_amount +msgid "Order subtotal per line." +msgstr "Subtotal del pedido por linea" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_total_amount +msgid "Order total amount" +msgstr "Importe total" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_total_amount +msgid "Order total amount without taxes" +msgstr "Importe del pedido actual, sin IVA." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_id +msgid "Packaging" +msgstr "Empaquetado" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Packaging Contained Qty" +msgstr "Ctd/caja" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Packaging Qty" +msgstr "Pedido por cajas" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_qty +msgid "Packaging Quantity" +msgstr "Cantidad de paquetes" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_contained_qty +msgid "Packaging Quantity Contained" +msgstr "Ctd contenida en el paquete" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_id +msgid "Packaging configured for this product." +msgstr "Empaquetado configurado para este producto." + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Prev Period" +msgstr "Ventas previas" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__price_unit +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__price_unit +msgid "Price Unit" +msgstr "Precio de compra sin descuento y sin iva para este proveedor." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_id +msgid "Product" +msgstr "Producto" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_name +msgid "Product Name" +msgstr "Nombre" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_code +msgid "Product reference" +msgstr "Ref" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_id +msgid "Product to be purchased from the vendor." +msgstr "[Referencia interna] y nombre del producto." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__price_unit +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__price_unit +msgid "Purchase price without discount and without VAT for this vendor." +msgstr "Precio de compra sin descuento y sin iva para este proveedor." + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Qty needed" +msgstr "Necesitas" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Qty scrapped" +msgstr "Mermas" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_contained_qty +msgid "Quantity contained in the selected packaging for this product." +msgstr "" +"Unidades por caja definidas en la pestaña inventario de la ficha de producto" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_qty +msgid "Quantity of packages to order for this product." +msgstr "" +"Número de paquetes a comprar para cubrir las ctd necesarias. Se puede " +"modificar este campo manualmente." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_received +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_received +msgid "Quantity of products already received for this order." +msgstr "" +"Cantidad de productos comprados durante el periodo (Entre la fecha de inicio" +" y fecha final)." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_delivered +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_delivered +msgid "" +"Quantity of products delivered to customers during the selected period." +msgstr "" +"Cantidad de productos vendidos durante el periodo (Entre la fecha de inicio " +"y fecha final)." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_delivered_prev +msgid "" +"Quantity of products sold during the previous period. The 'previous period' " +"is defined as the same number of days (Total days) immediately preceding." +msgstr "" +"Cantidad de productos vendidos durante el periodo anterior. El “periodo " +"anterior” se define como el mismo número de días (Días totales) " +"inmediatamente anteriores." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_included +msgid "" +"Quantity to be transferred to the order. This field can be modified " +"manually." +msgstr "" +"Cantidad que se va a trasladar al pedido. Se puede modificar este campo " +"manualmente." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_included_original +msgid "Quantity to order to have stock for the entire defined period." +msgstr "Cantidad a pedir para tener stock durante todo el periodo definido." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model,name:purchase_order_product_recommendation_supermarket.model_purchase_order_recommendation_line +msgid "Recommended product for current purchase order" +msgstr "Producto recomendado para el pedido de compra en curso" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model,name:purchase_order_product_recommendation_supermarket.model_purchase_order_recommendation +msgid "Recommended products for current purchase order" +msgstr "Productos recomendados para el pedido de compra en curso" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__line_amount +msgid "" +"Stablish a limit on how many recommendations you want to get.Leave it as 0 " +"to set no limit" +msgstr "" +"Establezca un límite de cuántas recomendaciones desea obtener. Déjelo en 0 " +"si no desea límite" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__stock_duration +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Stock Duration" +msgstr "Duración" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__subtotal_amount +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Subtotal Amount" +msgstr "Subtotal" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__total_days +msgid "Total days" +msgstr "Días analizados" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__total_days +msgid "" +"Total number of days between the start and end dates of the recommendation." +msgstr "" +"Número total de días entre las fechas de inicio y fin de la recomendación." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_available +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_available +msgid "Units Available" +msgstr "Cantidad de productos en stock" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_avg_delivered +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_avg_delivered +msgid "Units Avg Delivered" +msgstr "Media de ventas por día." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_avg_delivered_prev +msgid "Units Avg Delivered Prev" +msgstr "Media de consumo por día del periodo anterior" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_delivered +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_delivered +msgid "Units Delivered" +msgstr "" +"Cantidad de productos vendidos durante el periodo (Entre la fecha de inicio " +"y fecha final)." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_delivered_prev +msgid "Units Delivered Prev" +msgstr "" +"Cantidad de productos vendidos durante el periodo anterior. El “periodo " +"anterior” se define como el mismo número de días (Días totales) " +"inmediatamente anteriores." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_included +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_included +msgid "Units Included" +msgstr "Unidades incluídas" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_included_original +msgid "Units Included Original" +msgstr "Unidades incluidas original" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_received +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_received +msgid "Units Received" +msgstr "" +"Cantidad de productos comprados durante el periodo (Entre la fecha de inicio" +" y fecha final)." + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_scrapped +msgid "Units Scrapped" +msgstr "Ctd desechada" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_virtual_available +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_virtual_available +msgid "Units Virtual Available" +msgstr "" +"Cantidad de productos en stock + Cantidad de producto por venir (pedidos " +"confirmados)" diff --git a/purchase_order_product_recommendation_supermarket/i18n/purchase_order_product_recommendation_supermarket.pot b/purchase_order_product_recommendation_supermarket/i18n/purchase_order_product_recommendation_supermarket.pot new file mode 100644 index 0000000..ed2134e --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/i18n/purchase_order_product_recommendation_supermarket.pot @@ -0,0 +1,507 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_order_product_recommendation_supermarket +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-10-02 11:44+0000\n" +"PO-Revision-Date: 2025-10-02 11:44+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_template_form_po_min_suggest +msgid "Stock-out Periods" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_template__stock_out_period_ids +msgid "Stock-out Periods" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__start_date +msgid "Start Date" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__end_date +msgid "End Date" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__start_date +msgid "First calendar day when the product had zero stock in this period." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__end_date +msgid "Last calendar day (inclusive) the product remained without stock in this period." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__is_open +msgid "Open" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__days_out +msgid "Days without Stock" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__product_tmpl_id +msgid "Product Template" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__product_tmpl_id +msgid "Product template this stock-out period belongs to." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__is_open +msgid "Indicates the period is still ongoing (stock not yet restored)." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_stock_out_period__days_out +msgid "Total number of calendar days (inclusive) without stock for this period." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__include_previous_period +msgid "Include previous period stats" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__include_previous_period +msgid "If disabled, the previous period (same number of days immediately preceding) is NOT queried. This saves a read_group on stock move lines and skips zero-stock day analysis for that window." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_product_template__po_min_suggest_if_forecast_le_zero +msgid "Suggest minimum purchase when forecast <= 0" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_product_template__po_min_suggest_if_forecast_le_zero +msgid "If enabled, the purchase recommendation wizard will always propose at least 1 unit (or 1 full package when ordering by packages) when the forecasted stock is less or equal to 0." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_template_form_po_min_suggest +msgid "Purchase Recommendation" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_avg_delivered_prev +msgid "Average daily consumption during the previous period" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_avg_delivered +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_avg_delivered +msgid "Average daily consumption during the selected period." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__avg_days_between_orders +msgid "Average days between orders" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__avg_days_between_orders +msgid "Average number of days between orders for this vendor." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Avg Prev Period" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Calculate" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__currency_id +msgid "Currency" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_available +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_available +msgid "Current stock available in the warehouse." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__date_last_order +msgid "Date of last order" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__date_last_order +msgid "Date of the last order received from the vendor." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__days_without_stock +msgid "Days without stock" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_virtual_available +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_virtual_available +msgid "Forecasted stock, considering incoming and outgoing stock." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__ignore_zero_stock_days +msgid "" +"If enabled, days when the product stock was 0 or less will not be considered" +" in the daily sales calculation." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__ignore_zero_stock_days +msgid "Ignore days with zero stock" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_days +msgid "" +"Indicate for how many days the new order should cover the stock. If not set," +" the default module behavior is kept." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_by_packages +msgid "Indicates if the order should be made by packages." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_code +msgid "Internal reference of the product to be purchased from the vendor." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__last_order_total_amount +msgid "Last Order total amount" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__last_order_total_amount +msgid "Last Order total amount without taxes" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_name +msgid "Name of the product to be purchased from the vendor." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__days_without_stock +msgid "" +"Number of days in the selected period in which the on-hand quantity was 0." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__stock_duration +msgid "Number of days the current stock should last." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__line_amount +msgid "Number of recommendations" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_scrapped +msgid "Number of units recorded as scrap during the period" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_by_packages +msgid "Order by packages" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_days +msgid "Order coverage (days)" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__subtotal_amount +msgid "Order subtotal per line." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_total_amount +msgid "Order total amount" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__order_total_amount +msgid "Order total amount without taxes" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_id +msgid "Packaging" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Packaging Contained Qty" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Packaging Qty" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_qty +msgid "Packaging Quantity" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_contained_qty +msgid "Packaging Quantity Contained" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_id +msgid "Packaging configured for this product." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Prev Period" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__price_unit +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__price_unit +msgid "Price Unit" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_id +msgid "Product" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_name +msgid "Product Name" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_code +msgid "Product reference" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__product_id +msgid "Product to be purchased from the vendor." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__price_unit +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__price_unit +msgid "Purchase price without discount and without VAT for this vendor." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Qty needed" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Qty scrapped" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_contained_qty +msgid "Quantity contained in the selected packaging for this product." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__packaging_qty +msgid "Quantity of packages to order for this product." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_received +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_received +msgid "Quantity of products already received for this order." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_delivered +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_delivered +msgid "" +"Quantity of products delivered to customers during the selected period." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_delivered_prev +msgid "" +"Quantity of products sold during the previous period. The 'previous period' " +"is defined as the same number of days (Total days) immediately preceding." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_included +msgid "" +"Quantity to be transferred to the order. This field can be modified " +"manually." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_included +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_included_original +msgid "Quantity to order to have stock for the entire defined period." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model,name:purchase_order_product_recommendation_supermarket.model_purchase_order_recommendation_line +msgid "Recommended product for current purchase order" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model,name:purchase_order_product_recommendation_supermarket.model_purchase_order_recommendation +msgid "Recommended products for current purchase order" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__line_amount +msgid "" +"Stablish a limit on how many recommendations you want to get.Leave it as 0 " +"to set no limit" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__stock_duration +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Stock Duration" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__subtotal_amount +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_purchase_order_recommendation_wizard_form_supermarket +msgid "Subtotal Amount" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__total_days +msgid "Total days" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,help:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__total_days +msgid "" +"Total number of days between the start and end dates of the recommendation." +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_available +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_available +msgid "Units Available" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_avg_delivered +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_avg_delivered +msgid "Units Avg Delivered" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_avg_delivered_prev +msgid "Units Avg Delivered Prev" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_delivered +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_delivered +msgid "Units Delivered" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_delivered_prev +msgid "Units Delivered Prev" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_included +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_included +msgid "Units Included" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_included_original +msgid "Units Included Original" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_received +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_received +msgid "Units Received" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_scrapped +msgid "Units Scrapped" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation__units_virtual_available +#: model:ir.model.fields,field_description:purchase_order_product_recommendation_supermarket.field_purchase_order_recommendation_line__units_virtual_available +msgid "Units Virtual Available" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_form +msgid "Stock-out Period" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_tree +#: model:ir.actions.act_window,name:purchase_order_product_recommendation_supermarket.action_product_stock_out_period +#: model:ir.ui.menu,name:purchase_order_product_recommendation_supermarket.menu_product_stock_out_period +msgid "Stock-out Periods" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_search +msgid "Open" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_search +msgid "Closed" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_search +msgid "Search Stock-out Periods" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation_supermarket.view_product_stock_out_period_search +msgid "Open State" +msgstr "" + +#. module: purchase_order_product_recommendation_supermarket +#: model:ir.actions.act_window,help:purchase_order_product_recommendation_supermarket.action_product_stock_out_period +msgid "List of computed periods where a product template had zero stock. Open periods are still ongoing." +msgstr "" diff --git a/purchase_order_product_recommendation_supermarket/i18n_extra/es.po b/purchase_order_product_recommendation_supermarket/i18n_extra/es.po new file mode 100644 index 0000000..6b208cf --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/i18n_extra/es.po @@ -0,0 +1,311 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_order_product_recommendation +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-10-01 15:10+0000\n" +"PO-Revision-Date: 2025-10-01 15:10+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: purchase_order_product_recommendation +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation.purchase_order_recommendation_view_form +msgid "Accept" +msgstr "Aceptar" + +#. module: purchase_order_product_recommendation +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation.purchase_order_recommendation_view_form +msgid "Cancel" +msgstr "Cancelar" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,help:purchase_order_product_recommendation.field_purchase_order_recommendation__warehouse_ids +msgid "Constrain search to an specific warehouse" +msgstr "Restringir busqueda a un almacén concreto. Habitualmente esto no es relevante para supermercados con una sola tienda." + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__create_uid +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__create_date +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__currency_id +msgid "Currency" +msgstr "Moneda" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__date_begin +msgid "Date Begin" +msgstr "Fecha de inicio" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__date_end +msgid "Date End" +msgstr "Fecha final" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__display_name +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__display_name +msgid "Display Name" +msgstr "Nombre a mostrar" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,help:purchase_order_product_recommendation.field_purchase_order_recommendation__product_category_ids +msgid "Filter by product internal category" +msgstr "Filtrar por categorías de producto para obtener recomendaciones solo para aquellas que seleccionemos" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,help:purchase_order_product_recommendation.field_purchase_order_recommendation__date_end +msgid "Final date to compute recommendations." +msgstr "Fecha hasta la que se calculará el histórico de datos." + +#. module: purchase_order_product_recommendation +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation.purchase_order_recommendation_view_form +msgid "Forecasted Qty" +msgstr "Ctd Prevista" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__id +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__id +msgid "ID" +msgstr "ID (identificación)" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,help:purchase_order_product_recommendation.field_purchase_order_recommendation__date_begin +msgid "Initial date to compute recommendations." +msgstr "Fecha desde las que se calculará el histórico de datos." + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__is_modified +msgid "Is Modified" +msgstr "Está modificado" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation____last_update +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line____last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__write_uid +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__write_date +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__write_date +msgid "Last Updated on" +msgstr "Última actualización el" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__line_amount +msgid "Number of recommendations" +msgstr "Número de recomendaciones" + +#. module: purchase_order_product_recommendation +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation.purchase_order_recommendation_view_form +msgid "Price" +msgstr "Precio" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__price_unit +msgid "Price Unit" +msgstr "Precio de compra sin descuento y sin iva para este proveedor." + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__product_id +msgid "Product" +msgstr "Producto" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__product_category_ids +msgid "Product Categories" +msgstr "Categorías de productos" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__product_name +msgid "Product Name" +msgstr "Nombre" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__product_code +msgid "Product reference" +msgstr "Ref" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__line_ids +msgid "Products" +msgstr "Productos" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__purchase_line_id +msgid "Purchase Line" +msgstr "Línea de compra" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__order_id +msgid "Purchase Order" +msgstr "Pedido de compra" + +#. module: purchase_order_product_recommendation +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation.purchase_order_recommendation_view_form +msgid "Qty" +msgstr "Pedido por uds" + +#. module: purchase_order_product_recommendation +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation.purchase_order_recommendation_view_form +msgid "Qty Dlvd./day" +msgstr "Ventas/día" + +#. module: purchase_order_product_recommendation +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation.purchase_order_recommendation_view_form +msgid "Qty On Hand" +msgstr "Ctd a mano" + +#. module: purchase_order_product_recommendation +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation.purchase_order_recommendation_view_form +msgid "Qty Received" +msgstr "Compras" + +#. module: purchase_order_product_recommendation +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation.purchase_order_recommendation_view_form +msgid "Qty delivered" +msgstr "Ventas" + +#. module: purchase_order_product_recommendation +#: model_terms:ir.ui.view,arch_db:purchase_order_product_recommendation.purchase_order_form +msgid "Recommended Products" +msgstr "Productos recomendados" + +#. module: purchase_order_product_recommendation +#: model:ir.actions.act_window,name:purchase_order_product_recommendation.purchase_order_recommendation_action +msgid "Recommended Products for this Vendor" +msgstr "Productos recomendados por este vendedor" + +#. module: purchase_order_product_recommendation +#: model:ir.model,name:purchase_order_product_recommendation.model_purchase_order_recommendation_line +msgid "Recommended product for current purchase order" +msgstr "Producto recomendado para el pedido de compra en curso" + +#. module: purchase_order_product_recommendation +#: model:ir.model,name:purchase_order_product_recommendation.model_purchase_order_recommendation +msgid "Recommended products for current purchase order" +msgstr "Productos recomendados para el pedido de compra en curso" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,help:purchase_order_product_recommendation.field_purchase_order_recommendation__show_all_partner_products +msgid "Show all products with supplier infos for this supplier" +msgstr "Mostrar todos los productos con tarifa de compra para este proveedor. Es decir, muestra todos los productos en los que este proveedor esta asginado. Esto se configura en la pestaña de compras en la ficha de producto." + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__show_all_products +msgid "Show all purchasable products" +msgstr "Mostrar todos los productos comprables" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__show_all_partner_products +msgid "Show all supplier products" +msgstr "Mostrar todos los productos del proveedor" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,help:purchase_order_product_recommendation.field_purchase_order_recommendation__line_amount +msgid "" +"Stablish a limit on how many recommendations you want to get.Leave it as 0 " +"to set no limit" +msgstr "" +"Establezca un límite de cuántas recomendaciones desea obtener. Déjelo en 0 " +"si no desea límite" + +#. module: purchase_order_product_recommendation +#. odoo-python +#: code:addons/purchase_order_product_recommendation/wizards/purchase_order_recommendation.py:0 +#, python-format +msgid "This wizard is only valid for purchases" +msgstr "Este asistente solo es válido para compras" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__times_delivered +msgid "Times Delivered" +msgstr "Veces entregado" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__times_received +msgid "Times Received" +msgstr "Veces recibido" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__units_available +msgid "Units Available" +msgstr "Cantidad de productos en stock" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__units_avg_delivered +msgid "Units Avg Delivered" +msgstr "Media de ventas por día." + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__units_delivered +msgid "Units Delivered" +msgstr "Cantidad de productos vendidos durante el periodo (Entre la fecha de inicio y fecha final)." + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__units_included +msgid "Units Included" +msgstr "Unidades incluídas" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__units_received +msgid "Units Received" +msgstr "Cantidad de productos comprados durante el periodo (Entre la fecha de inicio y fecha final)." + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__units_virtual_available +msgid "Units Virtual Available" +msgstr "Cantidad de productos en stock + Cantidad de producto por venir (pedidos confirmados)" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,help:purchase_order_product_recommendation.field_purchase_order_recommendation__show_all_products +msgid "Useful if a product hasn't been selled by the partner yet" +msgstr "Solo útil para cuestiones muy concretas. Resulta útil si un producto aún no ha sido vendido por el proveedor por ejemplo." + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__partner_id +msgid "Vendor" +msgstr "Proveedor" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__warehouse_ids +msgid "Warehouse" +msgstr "Almacén" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation__warehouse_count +msgid "Warehouse Count" +msgstr "Nº de Almacenes" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,field_description:purchase_order_product_recommendation.field_purchase_order_recommendation_line__wizard_id +msgid "Wizard" +msgstr "Asistente" + +#. module: purchase_order_product_recommendation +#: model:ir.model.fields,help:purchase_order_product_recommendation.field_purchase_order_recommendation_line__partner_id +msgid "You can find a vendor by its Name, TIN, Email or Internal Reference." +msgstr "" +"Puede encontrar un proveedor por su nombre, NIF, correo electrónico o " +"referencia interna." diff --git a/purchase_order_product_recommendation_supermarket/models/__init__.py b/purchase_order_product_recommendation_supermarket/models/__init__.py new file mode 100644 index 0000000..e8fa8f6 --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/models/__init__.py @@ -0,0 +1 @@ +from . import product_template diff --git a/purchase_order_product_recommendation_supermarket/models/product_template.py b/purchase_order_product_recommendation_supermarket/models/product_template.py new file mode 100644 index 0000000..f97150d --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/models/product_template.py @@ -0,0 +1,107 @@ +from odoo import models, fields, api +from datetime import date + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + po_min_suggest_if_forecast_le_zero = fields.Boolean( + string="Suggest minimum purchase when forecast <= 0", + help="If enabled, the purchase recommendation wizard will always propose at least 1 unit (or 1 full package when ordering by packages) when the forecasted stock is less or equal to 0.", + ) + + stock_out_period_ids = fields.One2many( + "product.stock.out.period", + "product_tmpl_id", + string="Stock-out Periods", + help="Historical periods where this product had zero stock (qty_available <= 0).", + ) + + def cron_update_stock_out_periods(self): + """Scheduled every night: detect products currently without stock and + update (or create) an open stock-out period. While a period is open: + - end_date is kept updated each day with today's date + - days_out reflects (end_date - start_date).days + When stock returns the period is marked closed (is_open=False) but end_date + keeps the last day without stock (previous day if we consider stock restored today). + """ + # Consider only storable products + products = self.search([("type", "=", "product")]) + today = date.today() + # Prefetch qty_available efficiently (framework batches reads) + for product in products: + qty = product.qty_available + open_period = product.stock_out_period_ids.filtered(lambda p: p.is_open)[:1] + if qty <= 0: + if open_period: + # Refresh end_date to today (still open) + if open_period.end_date != today: + open_period.end_date = today + open_period._compute_days_out() + else: + self.env["product.stock.out.period"].create( + { + "product_tmpl_id": product.id, + "start_date": today, + "end_date": today, + "is_open": True, + } + ) + else: + if open_period: + # Close period: stock restored today -> last day without stock was yesterday + # We set end_date to max(start_date, today - 1) to avoid negative spans. + from datetime import timedelta + + closed_end = max(open_period.start_date, today - timedelta(days=1)) + if open_period.end_date != closed_end: + open_period.end_date = closed_end + open_period.is_open = False + open_period._compute_days_out() + + +class ProductStockOutPeriod(models.Model): + _name = "product.stock.out.period" + _description = "Product Stock-out Period" + _order = "start_date desc" + + product_tmpl_id = fields.Many2one( + "product.template", + required=True, + ondelete="cascade", + index=True, + string="Product Template", + help="Product template this stock-out period belongs to.", + ) + start_date = fields.Date( + required=True, + index=True, + string="Start Date", + help="First calendar day when the product had zero stock in this period.", + ) + end_date = fields.Date( + index=True, + string="End Date", + help="Last calendar day (inclusive) the product remained without stock in this period.", + ) + is_open = fields.Boolean( + string="Open", + default=False, + index=True, + help="Indicates the period is still ongoing (stock not yet restored).", + ) + days_out = fields.Integer( + string="Days without Stock", + compute="_compute_days_out", + store=True, + help="Total number of calendar days (inclusive) without stock for this period.", + ) + + @api.depends("start_date", "end_date", "is_open") + def _compute_days_out(self): + for rec in self: + if rec.start_date and rec.end_date: + # Inclusive count of days (both start and end) + rec.days_out = (rec.end_date - rec.start_date).days + 1 + else: + rec.days_out = 0 diff --git a/purchase_order_product_recommendation_supermarket/security/ir.model.access.csv b/purchase_order_product_recommendation_supermarket/security/ir.model.access.csv new file mode 100644 index 0000000..15f0899 --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_product_stock_out_period_user,access.product.stock.out.period.user,model_product_stock_out_period,base.group_user,1,0,0,0 diff --git a/purchase_order_product_recommendation_supermarket/static/src/scss/sticky_recommendation.scss b/purchase_order_product_recommendation_supermarket/static/src/scss/sticky_recommendation.scss new file mode 100644 index 0000000..3a87f8d --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/static/src/scss/sticky_recommendation.scss @@ -0,0 +1,104 @@ +/* Sticky header for purchase recommendation lines tree view */ +/* Make the tree container scrollable so position:sticky works inside */ +.o_purchase_recommendation_tree.o_list_view, /* defensive if Odoo adds class */ +.o_purchase_recommendation_tree { + max-height: 85vh; /* adjustable */ + overflow-y: auto; + position: relative; +} + +/* Target Odoo list table header cells */ +.o_purchase_recommendation_tree table thead th, +.o_purchase_recommendation_tree .o_list_table thead th, +.o_purchase_recommendation_tree table thead th > div, +.o_purchase_recommendation_tree .o_list_table thead th > div { + position: sticky !important; + top: 0 !important; + z-index: 7 !important; /* above possible indicators */ + background: var(--o-view-background-color, #f8f9fa) !important; + line-height: 1.2rem; + box-sizing: border-box; +} + +/* Extra background for nested inner elements */ +.o_purchase_recommendation_tree table thead th > div { + background: inherit; +} + +/* Subtle bottom border / shadow */ +.o_purchase_recommendation_tree table thead th::after { + content: ''; + position: absolute; + left: 0; + right: 0; + bottom: 0; + height: 1px; + background: rgba(0,0,0,0.15); + pointer-events: none; +} + +/* Prevent collapse issues that sometimes break sticky in Firefox */ +.o_purchase_recommendation_tree table { + border-collapse: separate !important; + border-spacing: 0; + width: 100%; +} + +/* Row separators (avoid double borders) */ +.o_purchase_recommendation_tree table tbody tr { + border-bottom: 1px solid #8f8d8d; +} +// .o_purchase_recommendation_tree table tbody tr:last-child { +// border-bottom: 0; +// } +// /* Remove previous cell-level borders */ +// .o_purchase_recommendation_tree table td, +// .o_purchase_recommendation_tree table th { +// border-bottom: none; +// } + +/* Zebra striping: only apply to rows without state-driven bg (avoid overriding decoration-* classes) */ +.o_purchase_recommendation_tree table tbody tr:nth-child(odd):not([class*='o_data_row_selected']):not(.o_list_view_group_header) td { + background-color: #ebe6e6; + border-bottom: 1px solid #8f8d8d; +} +.o_purchase_recommendation_tree table tbody tr:nth-child(even):not([class*='o_data_row_selected']):not(.o_list_view_group_header) td { + background-color: #ffffff; + border-bottom: 1px solid #8f8d8d; +} + +/* Keep Odoo decoration colors dominant (info/success/danger/muted) */ +.o_purchase_recommendation_tree table tbody tr[decoration-info] td, +.o_purchase_recommendation_tree table tbody tr[decoration-success] td, +.o_purchase_recommendation_tree table tbody tr[decoration-danger] td, +.o_purchase_recommendation_tree table tbody tr[decoration-muted] td { + background-color: inherit; +} + +/* Hover highlight (soft) */ +.o_purchase_recommendation_tree table tbody tr:hover td { + background-color: #eef6ff; +} +.o_purchase_recommendation_tree table tbody tr.o_data_row_selected td { + background-color: #d9ecff !important; +} + +/* Stronger text color for better contrast over zebra backgrounds */ +/* Force stronger text color (override potential nested span styles) */ +.o_purchase_recommendation_tree table tbody tr td, +.o_purchase_recommendation_tree table tbody tr td span, +.o_purchase_recommendation_tree table tbody tr td div { + color: #1b1b1b !important; +} + +/* Optional: indicate scroll with gradient at top when not at start */ +.o_purchase_recommendation_tree.is-scrolled::before { + content: ''; + position: sticky; + top: 0; + height: 0.35rem; + display: block; + background: linear-gradient(var(--o-view-background-color, #f8f9fa), rgba(248,249,250,0)); + z-index: 6; + pointer-events: none; +} diff --git a/purchase_order_product_recommendation_supermarket/views/product_stock_out_period_menu.xml b/purchase_order_product_recommendation_supermarket/views/product_stock_out_period_menu.xml new file mode 100644 index 0000000..8a45cb6 --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/views/product_stock_out_period_menu.xml @@ -0,0 +1,68 @@ + + + + + product.stock.out.period.tree + product.stock.out.period + + + + + + + + + + + + + + product.stock.out.period.form + product.stock.out.period + +
+ + + + + + + + + +
+
+
+ + + + product.stock.out.period.search + product.stock.out.period + + + + + + + + + + + + + + + + Stock-out Periods + product.stock.out.period + tree,form + + {"search_default_filter_open": 1} + +

List of computed periods where a product template had zero stock. Open periods are still ongoing.

+
+
+ + + +
\ No newline at end of file diff --git a/purchase_order_product_recommendation_supermarket/views/product_template_view.xml b/purchase_order_product_recommendation_supermarket/views/product_template_view.xml new file mode 100644 index 0000000..09d2982 --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/views/product_template_view.xml @@ -0,0 +1,36 @@ + + + + product.template.form.po.min.suggest + product.template + + + + + + + + + + + + + + + +
+ + + + + + + +
+
+
+
+
+
+
+
diff --git a/purchase_order_product_recommendation_supermarket/wizards/__init__.py b/purchase_order_product_recommendation_supermarket/wizards/__init__.py new file mode 100644 index 0000000..f0ed6f1 --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/wizards/__init__.py @@ -0,0 +1 @@ +from . import purchase_order_recommendation diff --git a/purchase_order_product_recommendation_supermarket/wizards/purchase_order_recommendation.py b/purchase_order_product_recommendation_supermarket/wizards/purchase_order_recommendation.py new file mode 100644 index 0000000..ad14f13 --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/wizards/purchase_order_recommendation.py @@ -0,0 +1,440 @@ +from odoo import api, fields, models +import math +from datetime import timedelta, datetime, time + + +class PurchaseOrderRecommendationSupermarketWizard(models.TransientModel): + _inherit = "purchase.order.recommendation" + + order_days = fields.Integer( + string="Order coverage (days)", + help="Indicate for how many days the new order should cover the stock. If not set, the default module behavior is kept.", + ) + order_by_packages = fields.Boolean( + string="Order by packages", + default=False, + help="Indicates if the order should be made by packages.", + ) + ignore_zero_stock_days = fields.Boolean( + string="Ignore days with zero stock", + default=False, + help="If enabled, days when the product stock was 0 or less will not be considered in the daily sales calculation.", + ) + include_previous_period = fields.Boolean( + string="Include previous period stats", + default=False, + help="If disabled, the previous period (same number of days immediately preceding) is NOT queried. This saves a read_group on stock move lines and skips zero-stock day analysis for that window.", + ) + total_days = fields.Integer( + string="Total days", + compute="_compute_total_days", + readonly=True, + help="Total number of days between the start and end dates of the recommendation.", + ) + avg_days_between_orders = fields.Float( + string="Average days between orders", + compute="_compute_avg_days_between_orders", + help="Average number of days between orders for this vendor.", + readonly=True, + ) + date_last_order = fields.Date( + string="Date of last order", + compute="_compute_avg_days_between_orders", + help="Date of the last order received from the vendor.", + readonly=True, + ) + currency_id = fields.Many2one( + related="order_id.currency_id", + readonly=True, + ) + order_total_amount = fields.Monetary( + string="Order total amount", + currency_field="currency_id", + compute="_compute_order_total_amount", + help="Order total amount without taxes", + readonly=True, + ) + line_amount = fields.Integer( + default=0, + ) + last_order_total_amount = fields.Monetary( + string="Last Order total amount", + currency_field="currency_id", + compute="_compute_avg_days_between_orders", + help="Last Order total amount without taxes", + readonly=True, + ) + + # Inherit fields to add help + price_unit = fields.Monetary( + help="Purchase price without discount and without VAT for this vendor." + ) + units_available = fields.Float( + help="Current stock available in the warehouse.", + ) + units_virtual_available = fields.Float( + help="Forecasted stock, considering incoming and outgoing stock.", + ) + units_received = fields.Float( + help="Quantity of products already received for this order.", + ) + units_delivered = fields.Float( + help="Quantity of products delivered to customers during the selected period.", + ) + units_avg_delivered = fields.Float( + help="Average daily consumption during the selected period.", + ) + units_included = fields.Float( + help="Quantity to order to have stock for the entire defined period.", + ) + + @api.depends("date_begin", "date_end") + def _compute_total_days(self): + for rec in self: + if rec.date_begin and rec.date_end: + rec.total_days = self._get_total_days() + else: + rec.total_days = 0 + + @api.depends("order_id") + def _compute_avg_days_between_orders(self): + if not self.order_id.partner_id: + self.avg_days_between_orders = 0.0 + return + + orders = self.env["purchase.order"].search( + [ + ("partner_id", "=", self.order_id.partner_id.id), + ("state", "in", ["purchase", "done"]), + ], + order="date_order asc", + ) + if orders: + self.date_last_order = ( + orders[-1].effective_date.date() + if orders[-1].effective_date + else orders[-1].date_planned.date() + ) + self.last_order_total_amount = orders[-1].amount_total + else: + self.date_last_order = False + self.last_order_total_amount = 0.0 + + dates = [o.date_order.date() for o in orders if o.date_order] + if len(dates) < 2: + self.avg_days_between_orders = 0.0 + return + + day_diffs = [ + (dates[i + 1] - dates[i]).days + for i in range(len(dates) - 1) + if (dates[i + 1] - dates[i]).days > 0 + ] + + if not day_diffs: + self.avg_days_between_orders = 0.0 + else: + self.avg_days_between_orders = sum(day_diffs) / len(day_diffs) + + @api.depends("line_ids") + def _compute_order_total_amount(self): + """Compute the total amount of the order.""" + if not self.order_id: + self.order_total_amount = 0.0 + return + total_amount = sum(line.subtotal_amount for line in self.line_ids) + self.order_total_amount = total_amount + + # Override the method to remove onchange and recalculate only by clicking the button + def _generate_recommendations(self): + super()._generate_recommendations() + + def regenerate_recommendations(self): + self._generate_recommendations() + return { + "type": "ir.actions.act_window", + "res_model": self._name, + "res_id": self.id, + "view_mode": "form", + "target": "new", + } + + def _prepare_wizard_line(self, vals, order_line=False): + """Used to create the wizard line""" + res = super()._prepare_wizard_line(vals, order_line=order_line) + product_id = order_line and order_line.product_id or vals["product_id"] + qty_to_order = res["units_included"] + + if self.ignore_zero_stock_days: + days_with_stock = self._get_total_days() - self._get_days_out_of_stock( + product_id + ) + res["units_avg_delivered"] = ( + vals.get("qty_delivered", 0) / days_with_stock + if days_with_stock != 0 + else 1 + ) + + if self.order_days != 0: + qty_to_order = max( + 0, + (self.order_days * res["units_avg_delivered"]) + - res["units_virtual_available"], + ) + + # Force a minimum suggested quantity when forecast <= 0 and product configured + # We apply this BEFORE packaging adjustment so packages logic can upscale it. + if ( + product_id.po_min_suggest_if_forecast_le_zero + and res["units_virtual_available"] <= 0 + ): + # If ordering by packages we later bump to one full package. + qty_to_order = max(qty_to_order, 1) + res["is_modified"] = True + res["units_included_original"] = qty_to_order + + # Adjust qty_to_order to packaging multiples if order_by_packages is checked + if self.order_by_packages and product_id.packaging_ids: + packaging_qty = product_id.packaging_ids[:1].qty + if packaging_qty: + qty_to_order = math.ceil(qty_to_order / packaging_qty) * packaging_qty + res["units_included"] = qty_to_order + + # Get quantities scrapped + domain = self._get_move_line_domain(product_id, src="internal", dst="inventory") + found_scrapped = self.env["stock.move.line"].read_group( + domain, ["product_id", "qty_done"], ["product_id"] + ) + if len(found_scrapped): + res["units_scrapped"] = found_scrapped[0]["qty_done"] + + if self.include_previous_period: + days = self._get_total_days() + prev_date_end = self.date_begin - timedelta(days=1) + prev_date_begin = self.date_begin - timedelta(days=days) + domain = self.with_context( + { + "period_date_begin": prev_date_begin, + "period_date_end": prev_date_end, + } + )._get_move_line_domain(product_id, src="internal", dst="customer") + found_previous_period = self.env["stock.move.line"].read_group( + domain, ["product_id", "qty_done"], ["product_id"] + ) + if len(found_previous_period): + res["units_delivered_prev"] = found_previous_period[0]["qty_done"] + if self.ignore_zero_stock_days: + days_with_stock = days - self.with_context( + { + "period_date_begin": prev_date_begin, + "period_date_end": prev_date_end, + } + )._get_days_out_of_stock(product_id) + res["units_avg_delivered_prev"] = ( + res["units_delivered_prev"] / days_with_stock + if days_with_stock != 0 + else 1 + ) + else: + res["units_avg_delivered_prev"] = ( + found_previous_period[0]["qty_done"] / days if days != 0 else 1 + ) + seller = product_id._select_seller( + partner_id=self.order_id.partner_id, + date=fields.Date.today(), + quantity=qty_to_order, + uom_id=product_id.uom_po_id, + ) + res.update(self._prepare_wizard_line_from_seller(res, seller)) + return res + + def action_accept(self): + super().action_accept() + for line in self.order_id.order_line: + if line.product_qty <= 0: + line.unlink() + + def _get_days_out_of_stock(self, product): + """Compute days without stock using precomputed periods (product.stock.out.period). + + A day is counted if it belongs to any stored stock-out period overlapping + the target window [date_from, date_to]. The period model stores end_date daily + (or closure day). + """ + date_from = self.env.context.get("period_date_begin", self.date_begin) + date_to = self.env.context.get("period_date_end", self.date_end) + if not date_from or not date_to: + return 0 + # Access template periods (product may be product.product or product.template) + product_tmpl = ( + product.product_tmpl_id if hasattr(product, "product_tmpl_id") else product + ) + periods = product_tmpl.stock_out_period_ids + total = 0 + for p in periods: + if not p.start_date or not p.end_date: + continue + # Overlap window + start = max(p.start_date, date_from) + end = min(p.end_date, date_to) + if start <= end: + total += (end - start).days + return total + + def _get_products(self): + """Overwrite because filter by cateogory is not working in the base method.""" + products = self._get_supplier_products() + # Filter products by category if set. + # It will apply to show_all_partner_products as well + if self.product_category_ids: + products = products.filtered( + lambda x: x.categ_id.id in self.product_category_ids.ids + ) + return products + + +class PurchaseOrderRecommendationLine(models.TransientModel): + _inherit = "purchase.order.recommendation.line" + + include_previous_period = fields.Boolean( + related="wizard_id.include_previous_period", store=False, readonly=True + ) + + packaging_id = fields.Many2one( + comodel_name="product.packaging", + string="Packaging", + help="Packaging configured for this product.", + compute="_compute_first_packaging_id", + readonly=True, + ) + packaging_qty = fields.Integer( + string="Packaging Quantity", + help="Quantity of packages to order for this product.", + compute="_compute_packaging_qty", + inverse="_inverse_packaging_qty", + store=True, + readonly=False, + ) + packaging_contained_qty = fields.Float( + string="Packaging Quantity Contained", + help="Quantity contained in the selected packaging for this product.", + related="packaging_id.qty", + readonly=True, + ) + days_without_stock = fields.Integer( + string="Days without stock", + compute="_compute_days_without_stock", + help="Number of days in the selected period in which the on-hand quantity was 0.", + readonly=True, + ) + units_scrapped = fields.Float( + readonly=True, help="Number of units recorded as scrap during the period" + ) + subtotal_amount = fields.Monetary( + string="Subtotal Amount", + compute="_compute_subtotal_amount", + help="Order subtotal per line.", + readonly=True, + ) + units_included_original = fields.Float( + string="Units Included Original", + help="Quantity to order to have stock for the entire defined period.", + readonly=True, + ) + stock_duration = fields.Float( + string="Stock Duration", + compute="_compute_stock_duration", + help="Number of days the current stock should last.", + readonly=True, + ) + units_delivered_prev = fields.Float( + help="Quantity of products sold during the previous period. The 'previous period' is defined as the same number of days (Total days) immediately preceding.", + readonly=True, + ) + units_avg_delivered_prev = fields.Float( + digits="Product Unit of Measure", + help="Average daily consumption during the previous period", + readonly=True, + ) + + # Inherit fields to add help + product_id = fields.Many2one( + help="Product to be purchased from the vendor.", + ) + product_name = fields.Char( + help="Name of the product to be purchased from the vendor.", + ) + product_code = fields.Char( + help="Internal reference of the product to be purchased from the vendor.", + ) + price_unit = fields.Monetary( + help="Purchase price without discount and without VAT for this vendor." + ) + units_available = fields.Float( + help="Current stock available in the warehouse.", + ) + units_virtual_available = fields.Float( + help="Forecasted stock, considering incoming and outgoing stock.", + ) + units_received = fields.Float( + help="Quantity of products already received for this order.", + ) + units_delivered = fields.Float( + help="Quantity of products delivered to customers during the selected period.", + ) + units_avg_delivered = fields.Float( + help="Average daily consumption during the selected period.", + ) + units_included = fields.Float( + help="Quantity to be transferred to the order. This field can be modified manually.", + ) + + @api.depends("units_included", "product_id") + def _compute_subtotal_amount(self): + for rec in self: + if rec.product_id and rec.units_included: + rec.subtotal_amount = rec.units_included * rec.price_unit + else: + rec.subtotal_amount = 0.0 + + @api.depends("wizard_id.date_begin", "wizard_id.date_end") + def _compute_days_without_stock(self): + for rec in self: + if rec.product_id: + rec.days_without_stock = rec.wizard_id._get_days_out_of_stock( + rec.product_id + ) + else: + rec.days_without_stock = 0 + + @api.onchange("packaging_qty") + def _inverse_packaging_qty(self): + for rec in self: + if rec.packaging_id and rec.packaging_id.qty: + rec.units_included = rec.packaging_qty * rec.packaging_id.qty + + @api.depends("packaging_id", "units_included") + def _compute_packaging_qty(self): + for rec in self: + if rec.packaging_id and rec.packaging_id.qty: + rec.packaging_qty = int(rec.units_included // rec.packaging_id.qty) + else: + rec.packaging_qty = 0 + + @api.depends("product_id") + def _compute_first_packaging_id(self): + for rec in self: + rec.packaging_id = ( + rec.product_id.packaging_ids[:1].id + if rec.product_id and rec.product_id.packaging_ids + else False + ) + + @api.depends("units_avg_delivered") + def _compute_stock_duration(self): + for rec in self: + rec.stock_duration = ( + rec.units_virtual_available / rec.units_avg_delivered + if rec.units_avg_delivered > 0 + else 0.0 + ) diff --git a/purchase_order_product_recommendation_supermarket/wizards/purchase_order_recommendation.xml b/purchase_order_product_recommendation_supermarket/wizards/purchase_order_recommendation.xml new file mode 100644 index 0000000..26089f4 --- /dev/null +++ b/purchase_order_product_recommendation_supermarket/wizards/purchase_order_recommendation.xml @@ -0,0 +1,66 @@ + + + + purchase.order.recommendation.wizard.form.supermarket + purchase.order.recommendation + + + +
+
+
+ + o_purchase_recommendation_tree + + + + + + + + + + + + + + + + + + hide + + + show + + + show + + + show + + + show + + + + + + + + + + + + + + + +
+
\ No newline at end of file diff --git a/purchase_subtotal_undiscounted/__init__.py b/purchase_subtotal_undiscounted/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/purchase_subtotal_undiscounted/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/purchase_subtotal_undiscounted/__manifest__.py b/purchase_subtotal_undiscounted/__manifest__.py new file mode 100644 index 0000000..6c4ff43 --- /dev/null +++ b/purchase_subtotal_undiscounted/__manifest__.py @@ -0,0 +1,15 @@ +{ + "name": "Purchase Subtotal Undiscounted", + "version": "16.0.1.0.0", + "depends": ["purchase_discount"], + "author": "Criptomart", + "category": "Purchases", + "description": "Show subtotal undiscounted in purchase order lines", + "data": [ + "views/purchase_order_line.xml", + ], + "license": "AGPL-3", + "installable": True, + "application": False, + "auto_install": False, +} diff --git a/purchase_subtotal_undiscounted/i18n/es.po b/purchase_subtotal_undiscounted/i18n/es.po new file mode 100644 index 0000000..dac9d54 --- /dev/null +++ b/purchase_subtotal_undiscounted/i18n/es.po @@ -0,0 +1,28 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_subtotal_undiscounted +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-12 08:22+0000\n" +"PO-Revision-Date: 2025-05-12 10:23+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.6\n" + +#. module: purchase_subtotal_undiscounted +#: model:ir.model,name:purchase_subtotal_undiscounted.model_purchase_order_line +msgid "Purchase Order Line" +msgstr "Línea de pedido de compra" + +#. module: purchase_subtotal_undiscounted +#: model:ir.model.fields,field_description:purchase_subtotal_undiscounted.field_purchase_order_line__price_subtotal_undiscounted +msgid "Subtotal witout Discount" +msgstr "Subtotal sin descuentos" diff --git a/purchase_subtotal_undiscounted/i18n/gl_ES.po b/purchase_subtotal_undiscounted/i18n/gl_ES.po new file mode 100644 index 0000000..482e734 --- /dev/null +++ b/purchase_subtotal_undiscounted/i18n/gl_ES.po @@ -0,0 +1,28 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_subtotal_undiscounted +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-12 08:22+0000\n" +"PO-Revision-Date: 2025-05-12 10:26+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: gl_ES\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 3.6\n" + +#. module: purchase_subtotal_undiscounted +#: model:ir.model,name:purchase_subtotal_undiscounted.model_purchase_order_line +msgid "Purchase Order Line" +msgstr "Liña pedido de compra" + +#. module: purchase_subtotal_undiscounted +#: model:ir.model.fields,field_description:purchase_subtotal_undiscounted.field_purchase_order_line__price_subtotal_undiscounted +msgid "Subtotal witout Discount" +msgstr "Subtotal sen Descontos" diff --git a/purchase_subtotal_undiscounted/i18n/purchase_subtotal_undiscounted.pot b/purchase_subtotal_undiscounted/i18n/purchase_subtotal_undiscounted.pot new file mode 100644 index 0000000..bd2f0a0 --- /dev/null +++ b/purchase_subtotal_undiscounted/i18n/purchase_subtotal_undiscounted.pot @@ -0,0 +1,26 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_subtotal_undiscounted +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-12 08:21+0000\n" +"PO-Revision-Date: 2025-05-12 08:21+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: purchase_subtotal_undiscounted +#: model:ir.model,name:purchase_subtotal_undiscounted.model_purchase_order_line +msgid "Purchase Order Line" +msgstr "" + +#. module: purchase_subtotal_undiscounted +#: model:ir.model.fields,field_description:purchase_subtotal_undiscounted.field_purchase_order_line__price_subtotal_undiscounted +msgid "Subtotal witout Discount" +msgstr "" diff --git a/purchase_subtotal_undiscounted/models/__init__.py b/purchase_subtotal_undiscounted/models/__init__.py new file mode 100644 index 0000000..fa6c0e4 --- /dev/null +++ b/purchase_subtotal_undiscounted/models/__init__.py @@ -0,0 +1 @@ +from . import purchase_order_line diff --git a/purchase_subtotal_undiscounted/models/purchase_order_line.py b/purchase_subtotal_undiscounted/models/purchase_order_line.py new file mode 100644 index 0000000..572efe5 --- /dev/null +++ b/purchase_subtotal_undiscounted/models/purchase_order_line.py @@ -0,0 +1,16 @@ +from odoo import models, fields, api + + +class PurchaseOrderLine(models.Model): + _inherit = "purchase.order.line" + + price_subtotal_undiscounted = fields.Monetary( + string="Subtotal witout Discount", + compute="_compute_price_subtotal_undiscounted", + currency_field="currency_id", + ) + + @api.depends("product_qty", "price_unit") + def _compute_price_subtotal_undiscounted(self): + for line in self: + line.price_subtotal_undiscounted = line.product_qty * line.price_unit diff --git a/purchase_subtotal_undiscounted/views/purchase_order_line.xml b/purchase_subtotal_undiscounted/views/purchase_order_line.xml new file mode 100644 index 0000000..b901cb1 --- /dev/null +++ b/purchase_subtotal_undiscounted/views/purchase_order_line.xml @@ -0,0 +1,15 @@ + + + purchase.order.form.undiscounted + purchase.order + + + + + + + 1 + + + + diff --git a/stock_inventory_category_concurrency/__init__.py b/stock_inventory_category_concurrency/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/stock_inventory_category_concurrency/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_inventory_category_concurrency/__manifest__.py b/stock_inventory_category_concurrency/__manifest__.py new file mode 100644 index 0000000..d92e23d --- /dev/null +++ b/stock_inventory_category_concurrency/__manifest__.py @@ -0,0 +1,14 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Stock Inventory Category Concurrency", + "version": "16.0.1.0.0", + "summary": "Permite abrir simultáneamente ajustes de inventario en categorías distintas", + "category": "Inventory", + "license": "AGPL-3", + "author": "Criptomart", + "depends": ["stock_inventory"], + "data": [ + "views/stock_quant_view.xml", + ], + "installable": True, +} diff --git a/stock_inventory_category_concurrency/i18n/es.po b/stock_inventory_category_concurrency/i18n/es.po new file mode 100644 index 0000000..102eb94 --- /dev/null +++ b/stock_inventory_category_concurrency/i18n/es.po @@ -0,0 +1,18 @@ +# Traducciones para stock_inventory_category_concurrency +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-10-07 00:00+0000\n" +"PO-Revision-Date: 2025-10-07 00:00+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_inventory_category_concurrency +#: model_terms:ir.ui.view,arch_db:stock_inventory_category_concurrency.stock_quant_search_category_filter +msgid "Product Category" +msgstr "Categoría de producto" diff --git a/stock_inventory_category_concurrency/i18n/stock_inventory_category_concurrency.pot b/stock_inventory_category_concurrency/i18n/stock_inventory_category_concurrency.pot new file mode 100644 index 0000000..d2e1655 --- /dev/null +++ b/stock_inventory_category_concurrency/i18n/stock_inventory_category_concurrency.pot @@ -0,0 +1,18 @@ +# Translation template for stock_inventory_category_concurrency +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-10-07 00:00+0000\n" +"PO-Revision-Date: 2025-10-07 00:00+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_inventory_category_concurrency +#: model_terms:ir.ui.view,arch_db:stock_inventory_category_concurrency.stock_quant_search_category_filter +msgid "Product Category" +msgstr "" diff --git a/stock_inventory_cost_info_sum/models/__init__.py b/stock_inventory_category_concurrency/models/__init__.py similarity index 100% rename from stock_inventory_cost_info_sum/models/__init__.py rename to stock_inventory_category_concurrency/models/__init__.py diff --git a/stock_inventory_category_concurrency/models/stock_inventory.py b/stock_inventory_category_concurrency/models/stock_inventory.py new file mode 100644 index 0000000..4b83067 --- /dev/null +++ b/stock_inventory_category_concurrency/models/stock_inventory.py @@ -0,0 +1,75 @@ +from odoo import _, models, fields +from odoo.exceptions import ValidationError + + +class StockQuant(models.Model): + _inherit = "stock.quant" + + product_categ_id = fields.Many2one( + related="product_tmpl_id.categ_id", + store=True, + index=True, + string="Product Category", + ) + + +class InventoryAdjustmentsGroup(models.Model): + _inherit = "stock.inventory" + + def action_state_to_in_progress(self): + self.ensure_one() + search_filter = [ + ( + "location_id", + "child_of" if not self.exclude_sublocation else "in", + self.location_ids.ids, + ), + ("to_do", "=", True), + ] + + error_field = "location_id" + error_message = _( + "There's already an Adjustment in Process " + "using one requested Location: %(names)s. " + "Blocking adjustments: %(blocking_names)s" + ) + + if self.product_ids: + search_filter.append(("product_id", "in", self.product_ids.ids)) + error_field = "product_id" + error_message = _( + "There are active adjustments for the requested products: %(names)s. " + "Blocking adjustments: %(blocking_names)s" + ) + elif self.category_id: + # Solo misma categoría exacta, sin OR hijos + search_filter.append(("product_id.categ_id", "=", self.category_id.id)) + error_field = "category_id" + error_message = _( + "There are active adjustments for the requested category: %(names)s. " + "Blocking adjustments: %(blocking_names)s" + ) + + quants = self.env["stock.quant"].search(search_filter) + if quants: + inventory_ids = self.env["stock.inventory"].search( + [("stock_quant_ids", "in", quants.ids), ("state", "=", "in_progress")] + ) + if inventory_ids: + blocking_names = ", ".join(inventory_ids.mapped("name")) + names = self._get_quant_joined_names(quants, error_field) + raise ValidationError( + error_message % {"names": names, "blocking_names": blocking_names} + ) + + quants = self._get_quants(self.location_ids) + self.write({"state": "in_progress", "stock_quant_ids": [(6, 0, quants.ids)]}) + quants.write( + { + "to_do": True, + "user_id": self.responsible_id, + "inventory_date": self.date, + "current_inventory_id": self.id, + } + ) + return diff --git a/stock_inventory_category_concurrency/views/stock_quant_view.xml b/stock_inventory_category_concurrency/views/stock_quant_view.xml new file mode 100644 index 0000000..92baaf4 --- /dev/null +++ b/stock_inventory_category_concurrency/views/stock_quant_view.xml @@ -0,0 +1,13 @@ + + + + stock.quant.search.category.filter + stock.quant + + + + + + + + \ No newline at end of file diff --git a/stock_inventory_cost_info_sum/__manifest__.py b/stock_inventory_cost_info_sum/__manifest__.py deleted file mode 100644 index 152ce51..0000000 --- a/stock_inventory_cost_info_sum/__manifest__.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2022 Criptomart -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -{ - 'name': 'Stock Inventory Cost Info Sum', - 'description': """ - Extends the OCA module stock_inventory_cost_info to store in the Inventory model the sum of the cost information of the inventory lines. This allows exporting and filtering by this field in the inventory adjustments tree view without having to export each inventory line.""", - 'version': '12.0.1.0.0', - 'license': 'AGPL-3', - 'author': 'Criptomart', - 'website': 'https://criptomart.net', - 'depends': [ - 'stock_inventory_cost_info', - ], - 'data': [ - 'views/stock_inventory.xml', - 'views/actions.xml', - ], - 'demo': [ - ], -} diff --git a/stock_inventory_cost_info_sum/models/stock_inventory.py b/stock_inventory_cost_info_sum/models/stock_inventory.py deleted file mode 100644 index 109bc01..0000000 --- a/stock_inventory_cost_info_sum/models/stock_inventory.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2022 Criptomart -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import api, fields, models, _ - - -class StockInventory(models.Model): - _inherit = 'stock.inventory' - - currency_id = fields.Many2one( - string="Currency", - related="company_id.currency_id", - readonly=True, - ) - adjustment_cost_sum = fields.Monetary( - string="Adjustment cost", - compute="_compute_adjustment_cost_sum", - store=True, - ) - - @api.depends("line_ids") - def _compute_adjustment_cost_sum(self): - for record in self: - record.adjustment_cost_sum = 0 - for line in record.line_ids: - record.adjustment_cost_sum += line.adjustment_cost \ No newline at end of file diff --git a/stock_inventory_cost_info_sum/views/actions.xml b/stock_inventory_cost_info_sum/views/actions.xml deleted file mode 100644 index 6e2ee1e..0000000 --- a/stock_inventory_cost_info_sum/views/actions.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - Recalculate Adjustment Cost - - - code - - records._compute_adjustment_cost_sum() - - - - \ No newline at end of file diff --git a/stock_inventory_cost_info_sum/views/stock_inventory.xml b/stock_inventory_cost_info_sum/views/stock_inventory.xml deleted file mode 100644 index 141a97b..0000000 --- a/stock_inventory_cost_info_sum/views/stock_inventory.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - stock.inventory.form (in stock_inventory_cost_info_sum) - stock.inventory - - - - - - - - - - - stock.inventory.tree (in stock_inventory_cost_info_sum) - stock.inventory - - - - - - - - - - diff --git a/stock_inventory_product_exhausted/README.rst b/stock_inventory_product_exhausted/README.rst new file mode 100644 index 0000000..9833e24 --- /dev/null +++ b/stock_inventory_product_exhausted/README.rst @@ -0,0 +1,49 @@ +========================================== +Stock Inventory Exhausted Products +========================================== + +This module extends the functionality of the `stock_inventory` module from the OCA/stock-logistics-warehouse repository to include exhausted products (with zero quantity) in inventory adjustments. + +In recent versions of Odoo, when a product reaches zero available quantity, its `stock.quant` is automatically deleted. This module allows creating quants with zero quantity for exhausted products when creating a new inventory adjustment, facilitating the physical counting of these products. + + +Features +======== + +* **Configurable field**: Includes a boolean field `include_exhausted_products` to enable/disable the functionality +* **Default behavior**: Maintains the original behavior of the base module when the option is disabled +* **Support for all selection types**: Works with manual selection, by category, specific product, or all products +* **Storable products only**: Creates quants only for products of type `product`, not for services +* **Prevents duplicates**: Does not create duplicate quants if they already exist for the product and location +* **User interface**: Field visible in the inventory adjustment form + +Configuration +============= + +The module requires no additional configuration. The `include_exhausted_products` field defaults to `False` to maintain compatibility with the original behavior. + +Usage +===== + +To use this module: + +#. Go to **Inventory > Operations > Inventory Adjustments** +#. Create a new inventory adjustment +#. Configure the desired locations and product selection +#. **Enable** the "Include Exhausted Products" field if you want to include products without stock +#. Click on "Start Inventory" + +Use cases +--------- + +**With the field enabled:** + +* Zero quantity quants will be created for products that have no stock in the selected locations +* Allows physically counting products that are exhausted in the system +* Useful for complete inventories where you want to verify that there really is no stock of certain products + +**With the field disabled:** + +* Standard behavior of the original module +* Only products that already have existing quants are included + diff --git a/stock_inventory_product_exhausted/__init__.py b/stock_inventory_product_exhausted/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/stock_inventory_product_exhausted/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_inventory_product_exhausted/__manifest__.py b/stock_inventory_product_exhausted/__manifest__.py new file mode 100644 index 0000000..bf84818 --- /dev/null +++ b/stock_inventory_product_exhausted/__manifest__.py @@ -0,0 +1,16 @@ +{ + "name": "Stock Inventory Exhausted Products", + "version": "16.0.1.0.0", + "development_status": "Beta", + "depends": ["stock_inventory"], + "author": "Criptomart", + "maintainers": ["luisnore"], + "website": "https://github.com/OCA/stock-logistics-warehouse", + "license": "AGPL-3", + "category": "Warehouse", + "summary": "Create quants for products with zero quantity in stock adjustments", + "data": [ + "views/stock_inventory.xml", + ], + "installable": True, +} diff --git a/stock_inventory_product_exhausted/i18n/ca_ES.po b/stock_inventory_product_exhausted/i18n/ca_ES.po new file mode 100644 index 0000000..a72119d --- /dev/null +++ b/stock_inventory_product_exhausted/i18n/ca_ES.po @@ -0,0 +1,38 @@ +# Catalan translation for stock_inventory_product_exhausted. +# Copyright (C) 2025 Criptomart +# This file is distributed under the same license as the stock_inventory_product_exhausted package. +# Luis Nore , 2025. +# +msgid "" +msgstr "" +"Project-Id-Version: stock_inventory_product_exhausted 16.0.1.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-10-16 08:00+0000\n" +"PO-Revision-Date: 2025-10-16 08:00+0000\n" +"Last-Translator: Luis Nore \n" +"Language-Team: Catalan\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_inventory_product_exhausted +#: model:ir.model.fields,field_description:stock_inventory_product_exhausted.field_stock_inventory__include_exhausted_products +msgid "Include Exhausted Products" +msgstr "Incloure Productes Esgotats" + +#. module: stock_inventory_product_exhausted +#: model:ir.model.fields,help:stock_inventory_product_exhausted.field_stock_inventory__include_exhausted_products +msgid "If enabled, products with zero stock will be included in the inventory adjustment by creating zero-quantity quants." +msgstr "Si està habilitat, els productes amb estoc zero s'inclouran en l'ajust d'inventari creant quants amb quantitat zero." + +#. module: stock_inventory_product_exhausted +#: model:ir.model,name:stock_inventory_product_exhausted.model_stock_inventory +msgid "Stock Inventory" +msgstr "Inventari d'Estoc" + +#. module: stock_inventory_product_exhausted +#: model:ir.model,name:stock_inventory_product_exhausted.model_stock_quant +msgid "Stock Quant" +msgstr "Quant d'Estoc" \ No newline at end of file diff --git a/stock_inventory_product_exhausted/i18n/es.po b/stock_inventory_product_exhausted/i18n/es.po new file mode 100644 index 0000000..13f3786 --- /dev/null +++ b/stock_inventory_product_exhausted/i18n/es.po @@ -0,0 +1,38 @@ +# Spanish translation for stock_inventory_product_exhausted. +# Copyright (C) 2025 Criptomart +# This file is distributed under the same license as the stock_inventory_product_exhausted package. +# Luis Nore , 2025. +# +msgid "" +msgstr "" +"Project-Id-Version: stock_inventory_product_exhausted 16.0.1.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-10-16 08:00+0000\n" +"PO-Revision-Date: 2025-10-16 08:00+0000\n" +"Last-Translator: Luis Nore \n" +"Language-Team: Spanish\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_inventory_product_exhausted +#: model:ir.model.fields,field_description:stock_inventory_product_exhausted.field_stock_inventory__include_exhausted_products +msgid "Include Exhausted Products" +msgstr "Incluir Productos Agotados" + +#. module: stock_inventory_product_exhausted +#: model:ir.model.fields,help:stock_inventory_product_exhausted.field_stock_inventory__include_exhausted_products +msgid "If enabled, products with zero stock will be included in the inventory adjustment by creating zero-quantity quants." +msgstr "Si está habilitado, los productos con stock cero se incluirán en el ajuste de inventario creando quants con cantidad cero." + +#. module: stock_inventory_product_exhausted +#: model:ir.model,name:stock_inventory_product_exhausted.model_stock_inventory +msgid "Stock Inventory" +msgstr "Inventario de Stock" + +#. module: stock_inventory_product_exhausted +#: model:ir.model,name:stock_inventory_product_exhausted.model_stock_quant +msgid "Stock Quant" +msgstr "Quant de Stock" \ No newline at end of file diff --git a/stock_inventory_product_exhausted/i18n/gl_ES.po b/stock_inventory_product_exhausted/i18n/gl_ES.po new file mode 100644 index 0000000..a04efba --- /dev/null +++ b/stock_inventory_product_exhausted/i18n/gl_ES.po @@ -0,0 +1,38 @@ +# Galician translation for stock_inventory_product_exhausted. +# Copyright (C) 2025 Criptomart +# This file is distributed under the same license as the stock_inventory_product_exhausted package. +# Luis Nore , 2025. +# +msgid "" +msgstr "" +"Project-Id-Version: stock_inventory_product_exhausted 16.0.1.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-10-16 08:00+0000\n" +"PO-Revision-Date: 2025-10-16 08:00+0000\n" +"Last-Translator: Luis Nore \n" +"Language-Team: Galician\n" +"Language: gl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_inventory_product_exhausted +#: model:ir.model.fields,field_description:stock_inventory_product_exhausted.field_stock_inventory__include_exhausted_products +msgid "Include Exhausted Products" +msgstr "Incluír Produtos Esgotados" + +#. module: stock_inventory_product_exhausted +#: model:ir.model.fields,help:stock_inventory_product_exhausted.field_stock_inventory__include_exhausted_products +msgid "If enabled, products with zero stock will be included in the inventory adjustment by creating zero-quantity quants." +msgstr "Se está habilitado, os produtos con stock cero incluiranse no axuste de inventario creando quants con cantidade cero." + +#. module: stock_inventory_product_exhausted +#: model:ir.model,name:stock_inventory_product_exhausted.model_stock_inventory +msgid "Stock Inventory" +msgstr "Inventario de Stock" + +#. module: stock_inventory_product_exhausted +#: model:ir.model,name:stock_inventory_product_exhausted.model_stock_quant +msgid "Stock Quant" +msgstr "Quant de Stock" \ No newline at end of file diff --git a/stock_inventory_product_exhausted/i18n/stock_inventory_product_exhausted.pot b/stock_inventory_product_exhausted/i18n/stock_inventory_product_exhausted.pot new file mode 100644 index 0000000..510aa34 --- /dev/null +++ b/stock_inventory_product_exhausted/i18n/stock_inventory_product_exhausted.pot @@ -0,0 +1,37 @@ +# Translation template for stock_inventory_product_exhausted. +# Copyright (C) 2025 Criptomart +# This file is distributed under the same license as the stock_inventory_product_exhausted package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: stock_inventory_product_exhausted 16.0.1.0.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-10-16 08:00+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. module: stock_inventory_product_exhausted +#: model:ir.model.fields,field_description:stock_inventory_product_exhausted.field_stock_inventory__include_exhausted_products +msgid "Include Exhausted Products" +msgstr "" + +#. module: stock_inventory_product_exhausted +#: model:ir.model.fields,help:stock_inventory_product_exhausted.field_stock_inventory__include_exhausted_products +msgid "If enabled, products with zero stock will be included in the inventory adjustment by creating zero-quantity quants." +msgstr "" + +#. module: stock_inventory_product_exhausted +#: model:ir.model,name:stock_inventory_product_exhausted.model_stock_inventory +msgid "Stock Inventory" +msgstr "" + +#. module: stock_inventory_product_exhausted +#: model:ir.model,name:stock_inventory_product_exhausted.model_stock_quant +msgid "Stock Quant" +msgstr "" \ No newline at end of file diff --git a/stock_inventory_product_exhausted/models/__init__.py b/stock_inventory_product_exhausted/models/__init__.py new file mode 100644 index 0000000..3553681 --- /dev/null +++ b/stock_inventory_product_exhausted/models/__init__.py @@ -0,0 +1 @@ +from . import stock_inventory diff --git a/stock_inventory_product_exhausted/models/stock_inventory.py b/stock_inventory_product_exhausted/models/stock_inventory.py new file mode 100644 index 0000000..d384c88 --- /dev/null +++ b/stock_inventory_product_exhausted/models/stock_inventory.py @@ -0,0 +1,113 @@ +# Copyright 2025 Your Name or Company +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, models, api, fields +import logging + +_logger = logging.getLogger(__name__) + + +class StockInventory(models.Model): + _inherit = "stock.inventory" + + include_exhausted_products = fields.Boolean( + string="Include Exhausted Products", + help="If enabled, products with zero stock will be included " + "in the inventory adjustment by creating zero-quantity quants.", + default=False, + ) + + def _create_zero_quants(self, locations, products): + """Create zero-quantity quants for products without existing quants. + + This method creates stock quants with zero quantity for storable products + that don't have existing quants in the specified locations. This allows + these products to be included in inventory adjustments even when they + have no current stock. + + Args: + locations (stock.location recordset): Locations to check + products (product.product recordset): Products to process + """ + Quant = self.env["stock.quant"] + + # Get existing quants to avoid duplicates + existing_quants = Quant.search( + [ + ("product_id", "in", products.ids), + ("location_id", "in", locations.ids), + ] + ) + existing_combinations = { + (q.product_id.id, q.location_id.id) for q in existing_quants + } + + quants_to_create = [] + for location in locations: + for product in products.filtered(lambda p: p.type == "product"): + if (product.id, location.id) not in existing_combinations: + _logger.debug( + "Creating zero quant for product %s in location %s", + product.name, + location.name, + ) + quants_to_create.append( + { + "product_id": product.id, + "location_id": location.id, + "quantity": 0, + "company_id": location.company_id.id or self.env.company.id, + } + ) + + if quants_to_create: + Quant.create(quants_to_create) + + def _get_quants(self, locations): + """Override to include zero-quantity quants when requested. + + This method extends the base functionality to optionally include + products with zero stock by creating zero-quantity quants before + retrieving the final quant list. + + Args: + locations (stock.location recordset): Locations for inventory + + Returns: + stock.quant recordset: Quants to include in inventory + """ + quants = super()._get_quants(locations) + + if self.include_exhausted_products: + # Determine products based on selection criteria + if self.product_selection == "category": + products = self.env["product.product"].search( + [("categ_id", "child_of", self.category_id.id)] + ) + elif self.product_selection in ("manual", "one", "lot"): + products = self.product_ids + else: # "all" + products = self.env["product.product"].search( + [("type", "=", "product")] + ) + + self._create_zero_quants(locations, products) + # Re-fetch quants to include newly created ones + return super()._get_quants(locations) + + return quants + + +class StockQuant(models.Model): + _inherit = "stock.quant" + + @api.model + def _unlink_zero_quants(self): + """Prevent automatic unlinking of zero quants. + + This method overrides the default behavior to prevent + zero quants from being automatically removed. + This may need review to ensure it doesn't conflict + with standard Odoo behavior. + """ + _logger.debug("Preventing automatic unlinking of zero quants") diff --git a/stock_inventory_product_exhausted/tests/__init__.py b/stock_inventory_product_exhausted/tests/__init__.py new file mode 100644 index 0000000..f5e8fea --- /dev/null +++ b/stock_inventory_product_exhausted/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_inventory_exhausted diff --git a/stock_inventory_product_exhausted/tests/test_stock_inventory_exhausted.py b/stock_inventory_product_exhausted/tests/test_stock_inventory_exhausted.py new file mode 100644 index 0000000..9018965 --- /dev/null +++ b/stock_inventory_product_exhausted/tests/test_stock_inventory_exhausted.py @@ -0,0 +1,227 @@ +from odoo.tests.common import TransactionCase + + +class TestStockInventoryExhausted(TransactionCase): + def setUp(self): + super().setUp() + # Create test products + self.product_with_stock = self.env["product.product"].create( + { + "name": "Product With Stock", + "type": "product", + "categ_id": self.env.ref("product.product_category_all").id, + } + ) + + self.product_without_stock = self.env["product.product"].create( + { + "name": "Product Without Stock", + "type": "product", + "categ_id": self.env.ref("product.product_category_all").id, + } + ) + + # Create test location + self.location = self.env["stock.location"].create( + { + "name": "Test Location", + "usage": "internal", + } + ) + + # Create initial stock for one product + self.env["stock.quant"].create( + { + "product_id": self.product_with_stock.id, + "location_id": self.location.id, + "quantity": 10.0, + } + ) + + def test_inventory_without_exhausted_products_flag(self): + """Test that without the flag, zero stock products are not included""" + inventory = self.env["stock.inventory"].create( + { + "name": "Test Inventory without flag", + "location_ids": [(6, 0, [self.location.id])], + "product_selection": "all", + "include_exhausted_products": False, + } + ) + + inventory.action_start() + + # Should only have quants for products with existing stock + self.assertTrue( + any( + q.product_id == self.product_with_stock + for q in inventory.stock_quant_ids + ) + ) + self.assertFalse( + any( + q.product_id == self.product_without_stock + for q in inventory.stock_quant_ids + ) + ) + + def test_inventory_with_exhausted_products_flag(self): + """Test that with the flag, zero stock products are included""" + inventory = self.env["stock.inventory"].create( + { + "name": "Test Inventory with flag", + "location_ids": [(6, 0, [self.location.id])], + "product_selection": "all", + "include_exhausted_products": True, + } + ) + + inventory.action_start() + + # Should have quants for both products (including zero stock product) + self.assertTrue( + any( + q.product_id == self.product_with_stock + for q in inventory.stock_quant_ids + ) + ) + self.assertTrue( + any( + q.product_id == self.product_without_stock + for q in inventory.stock_quant_ids + ) + ) + + # Check that zero stock product has quantity 0 + zero_quant = inventory.stock_quant_ids.filtered( + lambda q: q.product_id == self.product_without_stock + ) + self.assertEqual(zero_quant.quantity, 0.0) + + def test_inventory_manual_selection_with_exhausted_flag(self): + """Test manual product selection with exhausted products flag""" + inventory = self.env["stock.inventory"].create( + { + "name": "Test Manual Selection", + "location_ids": [(6, 0, [self.location.id])], + "product_selection": "manual", + "product_ids": [(6, 0, [self.product_without_stock.id])], + "include_exhausted_products": True, + } + ) + + inventory.action_start() + + # Should have quant for the selected product even if it has zero stock + self.assertTrue( + any( + q.product_id == self.product_without_stock + for q in inventory.stock_quant_ids + ) + ) + zero_quant = inventory.stock_quant_ids.filtered( + lambda q: q.product_id == self.product_without_stock + ) + self.assertEqual(zero_quant.quantity, 0.0) + + def test_inventory_category_selection_with_exhausted_flag(self): + """Test category selection with exhausted products flag""" + # Create a specific category + test_category = self.env["product.category"].create({"name": "Test Category"}) + + # Create product in this category + product_in_category = self.env["product.product"].create( + { + "name": "Product In Category", + "type": "product", + "categ_id": test_category.id, + } + ) + + inventory = self.env["stock.inventory"].create( + { + "name": "Test Category Selection", + "location_ids": [(6, 0, [self.location.id])], + "product_selection": "category", + "category_id": test_category.id, + "include_exhausted_products": True, + } + ) + + inventory.action_start() + + # Should have quant for the product in category even if it has zero stock + self.assertTrue( + any(q.product_id == product_in_category for q in inventory.stock_quant_ids) + ) + + def test_create_zero_quants_only_for_product_type(self): + """Test that zero quants are only created for products with type 'product'""" + # Create a service product + service_product = self.env["product.product"].create( + { + "name": "Service Product", + "type": "service", + } + ) + + inventory = self.env["stock.inventory"].create( + { + "name": "Test Service Product", + "location_ids": [(6, 0, [self.location.id])], + "product_selection": "manual", + "product_ids": [(6, 0, [service_product.id])], + "include_exhausted_products": True, + } + ) + + inventory.action_start() + + # Should not create quants for service products + self.assertFalse( + any(q.product_id == service_product for q in inventory.stock_quant_ids) + ) + + def test_no_duplicate_quants_created(self): + """Test that no duplicate quants are created if they already exist""" + # Create a quant with zero quantity manually + existing_quant = self.env["stock.quant"].create( + { + "product_id": self.product_without_stock.id, + "location_id": self.location.id, + "quantity": 0.0, + } + ) + + inventory = self.env["stock.inventory"].create( + { + "name": "Test No Duplicates", + "location_ids": [(6, 0, [self.location.id])], + "product_selection": "manual", + "product_ids": [(6, 0, [self.product_without_stock.id])], + "include_exhausted_products": True, + } + ) + + inventory.action_start() + + # Should use existing quant, not create a new one + quants_for_product = self.env["stock.quant"].search( + [ + ("product_id", "=", self.product_without_stock.id), + ("location_id", "=", self.location.id), + ] + ) + self.assertEqual(len(quants_for_product), 1) + self.assertEqual(quants_for_product.id, existing_quant.id) + + def test_field_default_value(self): + """Test that include_exhausted_products field defaults to False""" + inventory = self.env["stock.inventory"].create( + { + "name": "Test Default Value", + "location_ids": [(6, 0, [self.location.id])], + } + ) + + self.assertFalse(inventory.include_exhausted_products) diff --git a/stock_inventory_product_exhausted/views/stock_inventory.xml b/stock_inventory_product_exhausted/views/stock_inventory.xml new file mode 100644 index 0000000..021af95 --- /dev/null +++ b/stock_inventory_product_exhausted/views/stock_inventory.xml @@ -0,0 +1,12 @@ + + + stock.inventory.form.exhausted + stock.inventory + + + + + + + + \ No newline at end of file diff --git a/web_window_title/__init__.py b/web_window_title/__init__.py new file mode 100644 index 0000000..cde864b --- /dev/null +++ b/web_window_title/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- + +from . import models diff --git a/web_window_title/__manifest__.py b/web_window_title/__manifest__.py new file mode 100644 index 0000000..4cc0d43 --- /dev/null +++ b/web_window_title/__manifest__.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +{ + 'license': 'LGPL-3', + 'name': "Web Window Title", + 'summary': "The custom web window title", + 'author': "renjie ", + 'website': "https://renjie.me", + 'support': 'i@renjie.me', + 'category': 'Extra Tools', + 'version': '1.1', + 'depends': ['base_setup'], + 'demo': [ + 'data/demo.xml', + ], + 'data': [ + 'views/res_config.xml', + ], + 'images': [ + 'static/description/main_screenshot.png', + ], + 'assets': { + 'web.assets_backend': [ + 'web_window_title/static/src/js/web_window_title.js', + ], + }, + 'installable': True, + 'auto_install': False, + 'application': False, +} \ No newline at end of file diff --git a/web_window_title/data/demo.xml b/web_window_title/data/demo.xml new file mode 100644 index 0000000..937ce77 --- /dev/null +++ b/web_window_title/data/demo.xml @@ -0,0 +1,11 @@ + + + + + + web.base.title + Demo + + + + \ No newline at end of file diff --git a/web_window_title/models/__init__.py b/web_window_title/models/__init__.py new file mode 100644 index 0000000..b4db3f9 --- /dev/null +++ b/web_window_title/models/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- + +from . import ir_ui_view +from . import res_config diff --git a/web_window_title/models/ir_ui_view.py b/web_window_title/models/ir_ui_view.py new file mode 100644 index 0000000..633dbc9 --- /dev/null +++ b/web_window_title/models/ir_ui_view.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +import logging + +from odoo import api, fields, models, _ + +_logger = logging.getLogger(__name__) + +class View(models.Model): + _inherit = 'ir.ui.view' + + @api.model + def _render_template(self, template, values=None): + if template in ['web.login', 'web.webclient_bootstrap']: + if not values: + values = {} + values["title"] = self.env['ir.config_parameter'].sudo().get_param("web.base.title", "") + return super(View, self)._render_template(template, values) diff --git a/web_window_title/models/res_config.py b/web_window_title/models/res_config.py new file mode 100644 index 0000000..dcacb5d --- /dev/null +++ b/web_window_title/models/res_config.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +import logging + +from odoo import api, fields, models, _ + +_logger = logging.getLogger(__name__) + +CONFIG_PARAM_WEB_WINDOW_TITLE = "web.base.title" + +class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + + web_window_title = fields.Char('Window Title') + + @api.model + def get_values(self): + res = super(ResConfigSettings, self).get_values() + ir_config = self.env['ir.config_parameter'].sudo() + web_window_title = ir_config.get_param(CONFIG_PARAM_WEB_WINDOW_TITLE, default='') + res.update( + web_window_title=web_window_title + ) + return res + + def set_values(self): + super(ResConfigSettings, self).set_values() + ir_config = self.env['ir.config_parameter'].sudo() + ir_config.set_param(CONFIG_PARAM_WEB_WINDOW_TITLE, self.web_window_title or "") diff --git a/web_window_title/static/description/icon.png b/web_window_title/static/description/icon.png new file mode 100644 index 0000000..66573ce Binary files /dev/null and b/web_window_title/static/description/icon.png differ diff --git a/web_window_title/static/description/index.html b/web_window_title/static/description/index.html new file mode 100644 index 0000000..8a767a0 --- /dev/null +++ b/web_window_title/static/description/index.html @@ -0,0 +1,33 @@ +
+
+
+

Web Window Title

+

The custom web window title

+
+
+
+ +
+
+
+
+
+
+
+

Odoo/OpenERP Full Stack Customization and Development

+ + +
+
+
+ + + +
+
+
+
\ No newline at end of file diff --git a/web_window_title/static/description/main_screenshot.png b/web_window_title/static/description/main_screenshot.png new file mode 100644 index 0000000..fdca229 Binary files /dev/null and b/web_window_title/static/description/main_screenshot.png differ diff --git a/web_window_title/static/src/js/web_window_title.js b/web_window_title/static/src/js/web_window_title.js new file mode 100644 index 0000000..f6fd363 --- /dev/null +++ b/web_window_title/static/src/js/web_window_title.js @@ -0,0 +1,12 @@ +/** @odoo-module alias=web.window.title **/ + +import { WebClient } from "@web/webclient/webclient"; +import {patch} from "@web/core/utils/patch"; + +patch(WebClient.prototype, "Web Window Title", { + setup() { + const title = document.title; + this._super(); + this.title.setParts({ zopenerp: title }); + } +}); diff --git a/web_window_title/views/res_config.xml b/web_window_title/views/res_config.xml new file mode 100644 index 0000000..5a60970 --- /dev/null +++ b/web_window_title/views/res_config.xml @@ -0,0 +1,33 @@ + + + + + + res.config.settings.web.window.title + res.config.settings + + +
+

Window

+
+
+
+ Title +
+ The custom web window title +
+
+
+
+
+
+
+
+
+
+
+ +
+
\ No newline at end of file diff --git a/website_sale_product_sort_creation_date/__manifest__.py b/website_sale_product_sort_creation_date/__manifest__.py deleted file mode 100644 index 1a24024..0000000 --- a/website_sale_product_sort_creation_date/__manifest__.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2021 Criptomart -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -{ - 'name': 'Website Sale Product Sort Creation Date', - 'summary': 'Permite ordenar por la fecha de creación de los productos.', - 'version': '12.0.1.0.1', - 'development_status': 'Beta', - 'category': 'Website', - 'website': 'https://github.com/criptomart/obook', - 'author': 'Criptomart', - 'license': 'AGPL-3', - 'depends': [ - 'website', - 'website_sale_product_sort', - ], - 'data': [ - ], - 'application': False, - 'installable': True, -} diff --git a/website_sale_product_sort_creation_date/models/__init__.py b/website_sale_product_sort_creation_date/models/__init__.py deleted file mode 100644 index 40b75e0..0000000 --- a/website_sale_product_sort_creation_date/models/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from . import website - diff --git a/website_sale_product_sort_creation_date/models/website.py b/website_sale_product_sort_creation_date/models/website.py deleted file mode 100644 index cc705d6..0000000 --- a/website_sale_product_sort_creation_date/models/website.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2021 Criptomart -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). -from odoo import _, api, fields, models - - -class Website(models.Model): - _inherit = "website" - - @api.model - def _get_product_sort_criterias(self): - return [ - ('website_sequence desc', _('Relevance')), - ('list_price desc', _('Catalog price: High to Low')), - ('list_price asc', _('Catalog price: Low to High')), - ('name asc', _('Name - A to Z')), - ('name desc', _('Name - Z to A')), - ('create_date desc', 'Novedades'), - ] - - default_product_sort_criteria = fields.Selection( - selection='_get_product_sort_criterias', - string="Sort products by", - help="Default criteria for sorting products in the shop", - default='create_date desc', - required=True, - ) diff --git a/website_search_products/__manifest__.py b/website_search_products/__manifest__.py deleted file mode 100644 index 9f95ae0..0000000 --- a/website_search_products/__manifest__.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2022 Criptomart -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -{ - 'name': 'Website Search Products', - 'description': """ - Allows portal users to search products in a table with filters.""", - 'version': '12.0.1.0.0', - 'license': 'AGPL-3', - 'author': 'Criptomart', - 'website': 'https://criptomart.net', - 'depends': [ - "stock", - "website" - ], - 'data': [ - "data/menu.xml", - "data/ir_rule.xml", - "views/web_templates.xml" - ], - 'demo': [ - ], -} diff --git a/website_search_products/controllers/__init__.py b/website_search_products/controllers/__init__.py deleted file mode 100644 index 2f34e6e..0000000 --- a/website_search_products/controllers/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from . import controller diff --git a/website_search_products/controllers/controller.py b/website_search_products/controllers/controller.py deleted file mode 100644 index 463cb5e..0000000 --- a/website_search_products/controllers/controller.py +++ /dev/null @@ -1,34 +0,0 @@ - # -*- coding: utf-8 -*- -from odoo import http -from odoo.http import request -from odoo.addons.website.controllers.main import Website - -import logging -_logger = logging.getLogger(__name__) - -class IntentoryForm(http.Controller): - - @http.route(['/inventory/search'], type='http', auth="user", website=True) - def inventory_form(self, **post): - if not request.env['res.users'].browse(request.uid).has_group('base.group_portal')\ - and not request.env['res.users'].browse(request.uid).has_group('base.group_user'): - redirect = b'/web?' - return http.redirect_with_hash(redirect) - - products = request.env["product.template"].search([('active', '=', 'True'), ('available_in_pos', '=', 'True')]) - vals = {'products': products} - return request.render("website_search_products.web_list_products", vals) - - -class Website(Website): - - @http.route(website=True, auth="public") - def web_login(self, redirect=None, *args, **kw): - response = super(Website, self).web_login(redirect=redirect, *args, **kw) - if not redirect and request.params['login_success']: - if request.env['res.users'].browse(request.uid).has_group('base.group_user'): - redirect = b'/web?' + request.httprequest.query_string - else: - redirect = '/inventory/search' - return http.redirect_with_hash(redirect) - return response diff --git a/website_search_products/data/ir_rule.xml b/website_search_products/data/ir_rule.xml deleted file mode 100644 index 1c1ab21..0000000 --- a/website_search_products/data/ir_rule.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - Portal Consult Products - - - - - - - - - \ No newline at end of file diff --git a/website_search_products/data/menu.xml b/website_search_products/data/menu.xml deleted file mode 100644 index 397e0c8..0000000 --- a/website_search_products/data/menu.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - Products in Shop - /inventory/search - - 22 - - - diff --git a/website_search_products/i18n/es.po b/website_search_products/i18n/es.po deleted file mode 100644 index 6e3bc7a..0000000 --- a/website_search_products/i18n/es.po +++ /dev/null @@ -1,68 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * website_search_products -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 12.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-01-16 10:53+0000\n" -"PO-Revision-Date: 2023-01-16 12:07+0100\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: \n" -"Language: es\n" -"X-Generator: Poedit 2.3\n" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Category" -msgstr "Categoría" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Displayed products" -msgstr "Productos mostrados" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "In this table you can consult all the products available in the store" -msgstr "En esta tabla puedes consultar los productos disponibles en tienda" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Name" -msgstr "Nombre" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Price" -msgstr "Precio" - -#. module: website_search_products -#: model:website.menu,name:website_search_products.menu_partner_form -msgid "Products in Shop" -msgstr "Productos en tienda" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Products not found" -msgstr "Productos no encontrados" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Quantity" -msgstr "Cantidad" - -#. module: website_search_products -#: model:ir.model,name:website_search_products.model_stock_move -msgid "Stock Move" -msgstr "Movimiento de stock" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "UoM" -msgstr "UdM" diff --git a/website_search_products/i18n/website_search_products.pot b/website_search_products/i18n/website_search_products.pot deleted file mode 100644 index 5974cf3..0000000 --- a/website_search_products/i18n/website_search_products.pot +++ /dev/null @@ -1,67 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * website_search_products -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 12.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-01-16 10:53+0000\n" -"PO-Revision-Date: 2023-01-16 10:53+0000\n" -"Last-Translator: <>\n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Plural-Forms: \n" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Category" -msgstr "" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Displayed products" -msgstr "" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "In this table you can consult all the products available in the store" -msgstr "" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Name" -msgstr "" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Price" -msgstr "" - -#. module: website_search_products -#: model:website.menu,name:website_search_products.menu_partner_form -msgid "Products in Shop" -msgstr "" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Products not found" -msgstr "" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "Quantity" -msgstr "" - -#. module: website_search_products -#: model:ir.model,name:website_search_products.model_stock_move -msgid "Stock Move" -msgstr "" - -#. module: website_search_products -#: model_terms:ir.ui.view,arch_db:website_search_products.web_list_products -msgid "UoM" -msgstr "" - diff --git a/website_search_products/models/__init__.py b/website_search_products/models/__init__.py deleted file mode 100644 index c6fcb2f..0000000 --- a/website_search_products/models/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import stock_move diff --git a/website_search_products/models/stock_move.py b/website_search_products/models/stock_move.py deleted file mode 100644 index 81f9b07..0000000 --- a/website_search_products/models/stock_move.py +++ /dev/null @@ -1,59 +0,0 @@ -from odoo import tools -from odoo import models, fields, api - -from datetime import date,datetime -from dateutil.relativedelta import relativedelta - -import logging -_logger = logging.getLogger(__name__) - -class StockMove(models.Model): - _inherit = 'stock.move' - - @api.multi - def get_stock_moves_by_product(self, date_begin, date_end, location): - - if date_begin and date_end: - moves = self.env['stock.move'].search([ - '|', - ('location_id','=',int(location)), - ('location_dest_id','=',int(location)), - ('state', '=', 'done'), - ('date','>=',date_begin), - ('date','<=',date_end), - ]) - else: - return [] - - moves_grouped = {} - data = [] - - if moves: - for move in moves: - if move.product_id.id and move.product_id.type == 'product': - if not moves_grouped.get(move.product_id.id, False): - date_end_obj = datetime.strptime(date_end, '%Y-%m-%d').date() + relativedelta(days=1) - moves_grouped[move.product_id.id] = dict([]) - moves_grouped[move.product_id.id]['name'] = move.product_id.name - moves_grouped[move.product_id.id]['category'] = move.product_id.categ_id.name - moves_grouped[move.product_id.id]['list_price'] = move.product_id.list_price - moves_grouped[move.product_id.id]['qty_init'] = move.product_id.with_context({ - 'to_date':date_begin, - 'location': int(location) - }).qty_available - moves_grouped[move.product_id.id]['qty_end'] = move.product_id.with_context({ - 'to_date':date_end_obj, - 'location': int(location) - }).qty_available - - if not moves_grouped[move.product_id.id].get('in'): - moves_grouped[move.product_id.id]['in'] = 0.0 - if not moves_grouped[move.product_id.id].get('out'): - moves_grouped[move.product_id.id]['out'] = 0.0 - if int(move.location_id) == int(location): - moves_grouped[move.product_id.id]['out'] += move.product_qty - elif int(move.location_dest_id) == int(location): - moves_grouped[move.product_id.id]['in'] += move.product_qty - - data = list(moves_grouped.values()) - return data diff --git a/website_search_products/views/web_templates.xml b/website_search_products/views/web_templates.xml deleted file mode 100644 index 47c03be..0000000 --- a/website_search_products/views/web_templates.xml +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - -