diff --git a/addons/account/__manifest__.py b/addons/account/__manifest__.py index 2dfa849907f..c658b456f34 100644 --- a/addons/account/__manifest__.py +++ b/addons/account/__manifest__.py @@ -107,6 +107,7 @@ You could use this simplified accounting in case you work with an (external) acc 'account/static/src/js/legacy_section_and_note_fields_backend.js', 'account/static/src/js/tours/account.js', 'account/static/src/js/bills_upload.js', + 'account/static/src/js/legacy_bills_upload.js', 'account/static/src/js/account_selection.js', 'account/static/src/js/open_move_widget.js', 'account/static/src/js/account_move_form.js', diff --git a/addons/account/static/src/js/bills_upload.js b/addons/account/static/src/js/bills_upload.js index a5aa4e8498f..14656b57f8e 100644 --- a/addons/account/static/src/js/bills_upload.js +++ b/addons/account/static/src/js/bills_upload.js @@ -1,160 +1,157 @@ -odoo.define('account.upload.document', function (require) { -"use strict"; +/** @odoo-module **/ - var core = require('web.core'); - var qweb = core.qweb; - var ListController = require('web.ListController'); - var ListView = require('web.ListView'); - var KanbanController = require('web.KanbanController'); - var KanbanView = require('web.KanbanView'); - var viewRegistry = require('web.view_registry'); +import { registry } from "@web/core/registry"; +import { useService } from "@web/core/utils/hooks"; +import { listView } from "@web/views/list/list_view"; +import { ListRenderer } from "@web/views/list/list_renderer"; +import { ListController } from "@web/views/list/list_controller"; +import { kanbanView } from "@web/views/kanban/kanban_view"; +import { KanbanRenderer } from "@web/views/kanban/kanban_renderer"; +import { KanbanController } from "@web/views/kanban/kanban_controller"; +import { KanbanRecord } from "@web/views/kanban/kanban_record"; +import { FileUploader } from "@web/views/fields/file_handler"; - var UploadDocumentMixin = { - events: { - 'click .o_button_upload_document': '_onUpload', - 'change .o_account_document_upload .o_form_binary_form': '_onAddAttachment', - 'drop .o_drop_area': '_onDrop', - 'dragenter .o_content': '_highlight', - 'dragleave .o_drop_area': '_unhighlight', - 'dragover .o_drop_area': '_clear', - }, +const { Component, useState } = owl; - start: async function () { - // define a unique uploadId and a callback method - this.fileUploadID = _.uniqueId('account_bill_file_upload'); - $(window).on(this.fileUploadID, this._onFileUploaded.bind(this)); - let result = await this._super.apply(this, arguments); - await this.$(this._dropZone).prepend($(qweb.render('account.DocumentDropZone'))); - return result; - }, - - reload: async function () { - let result = await this._super.apply(this, arguments); - await this.$(this._dropZone).prepend($(qweb.render('account.DocumentDropZone'))); - return result; - }, - - _onAddAttachment: function (ev) { - // Auto submit form once we've selected an attachment - var $input = $(ev.currentTarget).find('input.o_input_file'); - if ($input.val() !== '') { - var $binaryForm = this.$('.o_account_document_upload form.o_form_binary_form'); - $binaryForm.submit(); - } - }, - - _onFileUploaded: function () { - // Callback once attachment have been created, create a document with attachment ids - var self = this; - var attachments = Array.prototype.slice.call(arguments, 1); - // Get id from result - var attachent_ids = attachments.reduce(function(filtered, record) { - if (record.id) { - filtered.push(record.id); - } - return filtered; - }, []); - return this._rpc({ - model: 'account.journal', - method: 'create_document_from_attachment', - args: ["", attachent_ids], - context: this.initialState.context, - }).then(function(result) { - self.do_action(result); - }).catch(function () { - // Reset the file input, allowing to select again the same file if needed - self.$('.o_account_document_upload .o_input_file').val(''); - }); - }, - - _createForm: function() { - // If hidden upload form don't exists, create it - var $formContainer = this.$('.o_content').find('.o_account_document_upload'); - if (!$formContainer.length) { - $formContainer = $(qweb.render('account.DocumentsHiddenUploadForm', {widget: this})); - $formContainer.appendTo(this.$('.o_content')); - } - }, - - _onUpload: function (ev) { - this._createForm(); - // Trigger the input to select a file - this.$('.o_account_document_upload .o_input_file').click(); - }, - - _highlight: function(ev) { - $('.o_drop_area').show(); - }, - - _unhighlight: function(ev) { - $('.o_drop_area').hide(); - }, - - _clear: function(ev) { - ev.preventDefault(); - }, - - _onDrop: function (ev) { - ev.preventDefault(); - this._createForm(); - if (ev.originalEvent.dataTransfer.files.length) { - this.$('.o_account_document_upload .o_input_file')[0].files = ev.originalEvent.dataTransfer.files; - this.$('.o_form_binary_form')[0].submit(); - } - this._unhighlight(ev); - }, +export class AccountFileUploader extends Component { + setup() { + this.orm = useService("orm"); + this.action = useService("action"); + this.attachmentIdsToProcess = []; } - var DocumentsListView = ListView.extend({ - config: Object.assign({}, ListView.prototype.config, { - Controller: ListController.extend({_dropZone: '.o_content'}, UploadDocumentMixin, { - buttons_template: 'DocumentsListView.buttons', - events: Object.assign({}, ListController.prototype.events, UploadDocumentMixin.events), - }), - }), - }); + async onFileUploaded(file) { + let att_data = { + name: file.name, + mimetype: file.type, + datas: file.data, + }; + const att_id = await this.orm.create("ir.attachment", att_data, { + ...this.props.extraContext, ...this.env.searchModel.context, + }); + this.attachmentIdsToProcess.push(att_id); + } - var DocumentsKanbanView = KanbanView.extend({ - config: Object.assign({}, KanbanView.prototype.config, { - Controller: KanbanController.extend({_dropZone: '.o_content'}, UploadDocumentMixin, { - buttons_template: 'DocumentsKanbanView.buttons', - events: Object.assign({}, KanbanController.prototype.events, UploadDocumentMixin.events), - }), - }), - }); + async onUploadComplete() { + const action = await this.orm.call("account.journal", "create_document_from_attachment", ["", this.attachmentIdsToProcess], { + context: { ...this.props.extraContext, ...this.env.searchModel.context }, + }); + this.attachmentIdsToProcess = []; + this.action.doAction(action); + } +} +AccountFileUploader.components = { + FileUploader, +}; +AccountFileUploader.template = "account.AccountFileUploader"; - var DashboardKanbanController = KanbanController.extend({_dropZone: '.o_kanban_record'}, UploadDocumentMixin, { - events: Object.assign({}, KanbanController.prototype.events, UploadDocumentMixin.events), +export class AccountDropZone extends Component { + setup() { + this.notificationService = useService("notification"); + } - _setJournalContext: function(ev) { - var kanbanRecord = $(ev.currentTarget).closest('.o_kanban_record').data('record'); - this.initialState.context['default_journal_id'] = kanbanRecord.id; - let journal_type = kanbanRecord.state.data.type; - if (journal_type == 'sale') { - this.initialState.context['default_move_type'] = 'out_invoice'; - } else if (journal_type == 'purchase') { - this.initialState.context['default_move_type'] = 'in_invoice'; - } - }, + onDrop(ev) { + const selector = '.account_file_uploader.o_input_file.o_hidden'; + // look for the closest uploader Input as it may have a context + let uploadInput = ev.target.closest('.o_drop_area').parentElement.querySelector(selector) || document.querySelector(selector); + let files = ev.dataTransfer ? ev.dataTransfer.files : false; + if (uploadInput && !!files) { + uploadInput.files = ev.dataTransfer.files; + uploadInput.dispatchEvent(new Event("change")); + } else { + this.notificationService.add( + this.env._t("Could not upload files"), + { + type: "danger", + }); + } + this.props.hideZone(); + } +} +AccountDropZone.defaultProps = { + hideZone: () => {}, +}; +AccountDropZone.template = "account.DropZone"; - _onUpload: function (ev) { - this._setJournalContext(ev); - UploadDocumentMixin._onUpload.apply(this, arguments); - }, +// Account Move List View +export class AccountMoveUploadListRenderer extends ListRenderer { + setup() { + super.setup(); + this.state.dropzoneVisible = false; + } +} +AccountMoveUploadListRenderer.template = "account.ListRenderer"; +AccountMoveUploadListRenderer.components = { + ...ListRenderer.components, + AccountDropZone, +}; - _onDrop: function (ev) { - this._setJournalContext(ev); - UploadDocumentMixin._onDrop.apply(this, arguments); - }, - }); +export class AccountMoveUploadListController extends ListController {} +AccountMoveUploadListController.components = { + ...ListController.components, + AccountFileUploader, +}; - var DashboardKanbanView = KanbanView.extend({ - config: Object.assign({}, KanbanView.prototype.config, { - Controller: DashboardKanbanController, - }), - }); +export const AccountMoveUploadListView = { + ...listView, + Controller: AccountMoveUploadListController, + Renderer: AccountMoveUploadListRenderer, + buttonTemplate: "account.ListView.Buttons", +}; - viewRegistry.add('account_tree', DocumentsListView); - viewRegistry.add('account_documents_kanban', DocumentsKanbanView); - viewRegistry.add('account_dashboard_kanban', DashboardKanbanView); -}); +// Account Move Kanban View +export class AccountMoveUploadKanbanRenderer extends KanbanRenderer { + setup() { + super.setup(); + this.state.dropzoneVisible = false; + } +} +AccountMoveUploadKanbanRenderer.template = "account.KanbanRenderer"; +AccountMoveUploadKanbanRenderer.components = { + ...KanbanRenderer.components, + AccountDropZone, +}; + +export class AccountMoveUploadKanbanController extends KanbanController {} +AccountMoveUploadKanbanController.components = { + ...KanbanController.components, + AccountFileUploader, +}; + +export const AccountMoveUploadKanbanView = { + ...kanbanView, + Controller: AccountMoveUploadKanbanController, + Renderer: AccountMoveUploadKanbanRenderer, + buttonTemplate: "account.KanbanView.Buttons", +}; + +// Accounting Dashboard +export class DashboardKanbanRecord extends KanbanRecord { + setup() { + super.setup(); + this.state = useState({ + dropzoneVisible: false, + }); + } +} +DashboardKanbanRecord.components = { + ...DashboardKanbanRecord.components, + AccountDropZone, + AccountFileUploader, +}; +DashboardKanbanRecord.template = "account.DashboardKanbanRecord"; + +export class DashboardKanbanRenderer extends KanbanRenderer {} +DashboardKanbanRenderer.components = { + ...KanbanRenderer.components, + KanbanRecord: DashboardKanbanRecord, +}; + +export const DashboardKanbanView = { + ...kanbanView, + Renderer: DashboardKanbanRenderer, +}; + +registry.category("views").add("account_tree", AccountMoveUploadListView); +registry.category("views").add("account_documents_kanban", AccountMoveUploadKanbanView); +registry.category("views").add("account_dashboard_kanban", DashboardKanbanView); diff --git a/addons/account/static/src/js/legacy_bills_upload.js b/addons/account/static/src/js/legacy_bills_upload.js new file mode 100644 index 00000000000..a5aa4e8498f --- /dev/null +++ b/addons/account/static/src/js/legacy_bills_upload.js @@ -0,0 +1,160 @@ +odoo.define('account.upload.document', function (require) { +"use strict"; + + var core = require('web.core'); + var qweb = core.qweb; + var ListController = require('web.ListController'); + var ListView = require('web.ListView'); + var KanbanController = require('web.KanbanController'); + var KanbanView = require('web.KanbanView'); + var viewRegistry = require('web.view_registry'); + + var UploadDocumentMixin = { + events: { + 'click .o_button_upload_document': '_onUpload', + 'change .o_account_document_upload .o_form_binary_form': '_onAddAttachment', + 'drop .o_drop_area': '_onDrop', + 'dragenter .o_content': '_highlight', + 'dragleave .o_drop_area': '_unhighlight', + 'dragover .o_drop_area': '_clear', + }, + + start: async function () { + // define a unique uploadId and a callback method + this.fileUploadID = _.uniqueId('account_bill_file_upload'); + $(window).on(this.fileUploadID, this._onFileUploaded.bind(this)); + let result = await this._super.apply(this, arguments); + await this.$(this._dropZone).prepend($(qweb.render('account.DocumentDropZone'))); + return result; + }, + + reload: async function () { + let result = await this._super.apply(this, arguments); + await this.$(this._dropZone).prepend($(qweb.render('account.DocumentDropZone'))); + return result; + }, + + _onAddAttachment: function (ev) { + // Auto submit form once we've selected an attachment + var $input = $(ev.currentTarget).find('input.o_input_file'); + if ($input.val() !== '') { + var $binaryForm = this.$('.o_account_document_upload form.o_form_binary_form'); + $binaryForm.submit(); + } + }, + + _onFileUploaded: function () { + // Callback once attachment have been created, create a document with attachment ids + var self = this; + var attachments = Array.prototype.slice.call(arguments, 1); + // Get id from result + var attachent_ids = attachments.reduce(function(filtered, record) { + if (record.id) { + filtered.push(record.id); + } + return filtered; + }, []); + return this._rpc({ + model: 'account.journal', + method: 'create_document_from_attachment', + args: ["", attachent_ids], + context: this.initialState.context, + }).then(function(result) { + self.do_action(result); + }).catch(function () { + // Reset the file input, allowing to select again the same file if needed + self.$('.o_account_document_upload .o_input_file').val(''); + }); + }, + + _createForm: function() { + // If hidden upload form don't exists, create it + var $formContainer = this.$('.o_content').find('.o_account_document_upload'); + if (!$formContainer.length) { + $formContainer = $(qweb.render('account.DocumentsHiddenUploadForm', {widget: this})); + $formContainer.appendTo(this.$('.o_content')); + } + }, + + _onUpload: function (ev) { + this._createForm(); + // Trigger the input to select a file + this.$('.o_account_document_upload .o_input_file').click(); + }, + + _highlight: function(ev) { + $('.o_drop_area').show(); + }, + + _unhighlight: function(ev) { + $('.o_drop_area').hide(); + }, + + _clear: function(ev) { + ev.preventDefault(); + }, + + _onDrop: function (ev) { + ev.preventDefault(); + this._createForm(); + if (ev.originalEvent.dataTransfer.files.length) { + this.$('.o_account_document_upload .o_input_file')[0].files = ev.originalEvent.dataTransfer.files; + this.$('.o_form_binary_form')[0].submit(); + } + this._unhighlight(ev); + }, + } + + var DocumentsListView = ListView.extend({ + config: Object.assign({}, ListView.prototype.config, { + Controller: ListController.extend({_dropZone: '.o_content'}, UploadDocumentMixin, { + buttons_template: 'DocumentsListView.buttons', + events: Object.assign({}, ListController.prototype.events, UploadDocumentMixin.events), + }), + }), + }); + + var DocumentsKanbanView = KanbanView.extend({ + config: Object.assign({}, KanbanView.prototype.config, { + Controller: KanbanController.extend({_dropZone: '.o_content'}, UploadDocumentMixin, { + buttons_template: 'DocumentsKanbanView.buttons', + events: Object.assign({}, KanbanController.prototype.events, UploadDocumentMixin.events), + }), + }), + }); + + var DashboardKanbanController = KanbanController.extend({_dropZone: '.o_kanban_record'}, UploadDocumentMixin, { + events: Object.assign({}, KanbanController.prototype.events, UploadDocumentMixin.events), + + _setJournalContext: function(ev) { + var kanbanRecord = $(ev.currentTarget).closest('.o_kanban_record').data('record'); + this.initialState.context['default_journal_id'] = kanbanRecord.id; + let journal_type = kanbanRecord.state.data.type; + if (journal_type == 'sale') { + this.initialState.context['default_move_type'] = 'out_invoice'; + } else if (journal_type == 'purchase') { + this.initialState.context['default_move_type'] = 'in_invoice'; + } + }, + + _onUpload: function (ev) { + this._setJournalContext(ev); + UploadDocumentMixin._onUpload.apply(this, arguments); + }, + + _onDrop: function (ev) { + this._setJournalContext(ev); + UploadDocumentMixin._onDrop.apply(this, arguments); + }, + }); + + var DashboardKanbanView = KanbanView.extend({ + config: Object.assign({}, KanbanView.prototype.config, { + Controller: DashboardKanbanController, + }), + }); + + viewRegistry.add('account_tree', DocumentsListView); + viewRegistry.add('account_documents_kanban', DocumentsKanbanView); + viewRegistry.add('account_dashboard_kanban', DashboardKanbanView); +}); diff --git a/addons/account/static/src/scss/bills_upload.scss b/addons/account/static/src/scss/bills_upload.scss index b018483ef3f..6dabf015602 100644 --- a/addons/account/static/src/scss/bills_upload.scss +++ b/addons/account/static/src/scss/bills_upload.scss @@ -1,5 +1,4 @@ .o_drop_area { - display: none; width: 100%; height: 100%; position: absolute; diff --git a/addons/account/static/src/xml/bills_upload_views.xml b/addons/account/static/src/xml/bills_upload_views.xml index 136566f8c54..072d88154d7 100644 --- a/addons/account/static/src/xml/bills_upload_views.xml +++ b/addons/account/static/src/xml/bills_upload_views.xml @@ -1,37 +1,88 @@ - - - - - - - - - - - - - - - - - -
+ +
+ + +
+ + + + + +
+
+ + + + + + + () => state.dropzoneVisible = true + + + + + + + + + () => state.dropzoneVisible = true + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ diff --git a/addons/account/static/src/xml/legacy_bills_upload_views.xml b/addons/account/static/src/xml/legacy_bills_upload_views.xml new file mode 100644 index 00000000000..136566f8c54 --- /dev/null +++ b/addons/account/static/src/xml/legacy_bills_upload_views.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + +
+ +
+
+
diff --git a/addons/account/views/account_journal_dashboard_view.xml b/addons/account/views/account_journal_dashboard_view.xml index 342bdc58284..6770a23e935 100644 --- a/addons/account/views/account_journal_dashboard_view.xml +++ b/addons/account/views/account_journal_dashboard_view.xml @@ -18,6 +18,7 @@
+
@@ -36,6 +37,17 @@
+ + + + +