diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/__init__.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js new file mode 100644 index 000000000..657146f2b --- /dev/null +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.js @@ -0,0 +1,6 @@ +// Copyright (c) 2019, Bloom Stack, Inc and contributors +// For license information, please see license.txt + +frappe.ui.form.on("Authorization Request", { + +}); diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json new file mode 100644 index 000000000..c1df7f9b7 --- /dev/null +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.json @@ -0,0 +1,495 @@ +{ + "allow_copy": 0, + "allow_events_in_timeline": 0, + "allow_guest_to_view": 0, + "allow_import": 0, + "allow_rename": 0, + "autoname": "AR.######", + "beta": 0, + "creation": "2019-05-10 04:18:42.975410", + "custom": 0, + "docstatus": 0, + "doctype": "DocType", + "document_type": "", + "editable_grid": 0, + "engine": "InnoDB", + "fields": [ + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "linked_doctype", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Linked DocType", + "length": 0, + "no_copy": 0, + "options": "DocType", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "linked_docname", + "fieldtype": "Dynamic Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 1, + "in_standard_filter": 0, + "label": "Linked DocName", + "length": 0, + "no_copy": 0, + "options": "linked_doctype", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "default": "", + "fetch_if_empty": 0, + "fieldname": "authorizer_email", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Authorizer Email", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 1, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "cb", + "fieldtype": "Column Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "signature", + "fieldtype": "Signature", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Signature", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "signee_name", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Signee Name", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "section_break_4", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "token", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Token", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "token_generated_on", + "fieldtype": "Datetime", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Token Generated On", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "request_link", + "fieldtype": "Data", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Request Link", + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "section_break_13", + "fieldtype": "Section Break", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "length": 0, + "no_copy": 0, + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 1, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "status", + "fieldtype": "Select", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Status", + "length": 0, + "no_copy": 0, + "options": "Request Sent\nApproved\nRejected", + "permlevel": 0, + "precision": "", + "print_hide": 0, + "print_hide_if_no_value": 0, + "read_only": 0, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + }, + { + "allow_bulk_edit": 0, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "columns": 0, + "fetch_if_empty": 0, + "fieldname": "amended_from", + "fieldtype": "Link", + "hidden": 0, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_standard_filter": 0, + "label": "Amended From", + "length": 0, + "no_copy": 1, + "options": "Authorization Request", + "permlevel": 0, + "print_hide": 1, + "print_hide_if_no_value": 0, + "read_only": 1, + "remember_last_selected_value": 0, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "set_only_once": 0, + "translatable": 0, + "unique": 0 + } + ], + "has_web_view": 0, + "hide_heading": 0, + "hide_toolbar": 0, + "idx": 0, + "image_view": 0, + "in_create": 0, + "is_submittable": 1, + "issingle": 0, + "istable": 0, + "max_attachments": 0, + "modified": "2019-06-06 03:26:19.653725", + "modified_by": "Administrator", + "module": "Bloomstack Core", + "name": "Authorization Request", + "name_case": "", + "owner": "Administrator", + "permissions": [ + { + "amend": 0, + "cancel": 0, + "create": 1, + "delete": 1, + "email": 1, + "export": 1, + "if_owner": 0, + "import": 0, + "permlevel": 0, + "print": 1, + "read": 1, + "report": 1, + "role": "System Manager", + "set_user_permissions": 0, + "share": 1, + "submit": 0, + "write": 1 + } + ], + "quick_entry": 1, + "read_only": 0, + "read_only_onload": 0, + "show_name_in_global_search": 0, + "sort_field": "modified", + "sort_order": "ASC", + "track_changes": 1, + "track_seen": 0, + "track_views": 0 +} \ No newline at end of file diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py new file mode 100644 index 000000000..eef97cb8d --- /dev/null +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/authorization_request.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019, Bloom Stack, Inc and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model.document import Document +from frappe.utils import now_datetime +from frappe.utils.data import get_url +from erpnext import get_default_company + +class AuthorizationRequest(Document): + def after_insert(self): + self.generate_token() + self.send_authorization_request() + self.status = "Request Sent" + + def generate_token(self): + self.token = frappe.generate_hash(self.name, 32) + self.token_generated_on = now_datetime() + self.request_link = "{0}/authorize_document?token={1}&name={2}".format(get_url(), self.token, self.name) + self.save() + + def send_authorization_request(self): + """ + Email the link to user for them to authorize the document + """ + + doc = frappe.get_doc(self.linked_doctype, self.linked_docname) + company = doc.company if hasattr(doc, 'company') else get_default_company() + + subject = "{0} requests your authorization on {1}".format(company, self.linked_doctype) + message = frappe.render_template("templates/emails/authorization_request.html", { + "authorization_request": self, + }) + + frappe.sendmail(recipients=[self.authorizer_email], subject=subject, message=message) \ No newline at end of file diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.js b/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.js new file mode 100644 index 000000000..ec8cade49 --- /dev/null +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +// rename this file from _test_[name] to test_[name] to activate +// and remove above this line + +QUnit.test("test: Authorization Request", function (assert) { + let done = assert.async(); + + // number of asserts + assert.expect(1); + + frappe.run_serially([ + // insert a new Authorization Request + () => frappe.tests.make('Authorization Request', [ + // values to be set + {key: 'value'} + ]), + () => { + assert.equal(cur_frm.doc.key, 'value'); + }, + () => done() + ]); + +}); diff --git a/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.py b/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.py new file mode 100644 index 000000000..04f34047c --- /dev/null +++ b/bloomstack_core/bloomstack_core/doctype/authorization_request/test_authorization_request.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2019, Bloom Stack, Inc and Contributors +# See license.txt +from __future__ import unicode_literals + +import frappe +import unittest + +class TestAuthorizationRequest(unittest.TestCase): + pass diff --git a/bloomstack_core/hooks.py b/bloomstack_core/hooks.py index 4e523ebe0..1759cf385 100755 --- a/bloomstack_core/hooks.py +++ b/bloomstack_core/hooks.py @@ -53,7 +53,9 @@ "Company": "public/js/company.js", "Supplier": "public/js/supplier.js", "Item": "public/js/item.js", - "Batch": "public/js/batch.js" + "Batch": "public/js/batch.js", + "Quotation": "public/js/quotation.js", + "Contract": "public/js/contract.js" } # doctype_list_js = {"doctype" : "public/js/doctype_list.js"} # doctype_tree_js = {"doctype" : "public/js/doctype_tree.js"} diff --git a/bloomstack_core/public/js/contract.js b/bloomstack_core/public/js/contract.js new file mode 100644 index 000000000..fc124a25b --- /dev/null +++ b/bloomstack_core/public/js/contract.js @@ -0,0 +1,44 @@ +frappe.ui.form.on("Contract", { + refresh: (frm) => { + if (!frm.is_new() && frm.doc.docstatus === 0) { + if (!frm.doc.customer_signature) { + frm.add_custom_button(__("Authorize"), () => { + frappe.prompt([ + { + "label": "Contact Email", + "fieldtype": "Data", + "options": "Email", + "fieldname": "contact_email", + "default": frm.doc.party_user, + "reqd": 1 + }, + { + "label": "Contact Person", + "fieldtype": "Data", + "fieldname": "contact_person", + "default": frm.doc.party_name + } + ], + function (data) { + frappe.call({ + method: "bloomstack_core.utils.create_authorization_request", + args: { + dt: frm.doc.doctype, + dn: frm.doc.name, + contact_email: data.contact_email, + contact_name: data.contact_person + }, + callback: (r) => { + if (!r.exc) { + frappe.msgprint(__(`${frm.doc.name} has been successfully sent to ${data.contact_email}`)) + } + } + }) + }, + __("Send Authorization Request")) + }).addClass("btn-primary"); + + } + } + }, +}); \ No newline at end of file diff --git a/bloomstack_core/public/js/quotation.js b/bloomstack_core/public/js/quotation.js new file mode 100644 index 000000000..bcae8f346 --- /dev/null +++ b/bloomstack_core/public/js/quotation.js @@ -0,0 +1,45 @@ +frappe.ui.form.on('Quotation', { + refresh: (frm) => { + if (!frm.is_new() && frm.doc.docstatus === 0) { + if (!frm.doc.customer_signature) { + frm.add_custom_button(__("Authorize"), () => { + frappe.prompt([ + { + "label": "Contact Email", + "fieldtype": "Data", + "options": "Email", + "fieldname": "contact_email", + "default": frm.doc.contact_email, + "reqd": 1 + }, + { + "label": "Contact Person", + "fieldtype": "Data", + "fieldname": "contact_person", + "default": frm.doc.contact_person + } + ], + function (data) { + frappe.call({ + method: "bloomstack_core.utils.create_authorization_request", + args: { + dt: frm.doc.doctype, + dn: frm.doc.name, + contact_email: data.contact_email, + contact_name: data.contact_person + }, + callback: (r) => { + if (!r.exc) { + frappe.msgprint(__(`The document ${frm.doc.name} has been successfully emailed to ${data.contact_person}`)) + } + } + }) + }, + __("Send Authorization Request")) + }).addClass("btn-primary"); + + } + } + }, + +}); diff --git a/bloomstack_core/templates/emails/authorization_request.html b/bloomstack_core/templates/emails/authorization_request.html new file mode 100644 index 000000000..cc97a5d61 --- /dev/null +++ b/bloomstack_core/templates/emails/authorization_request.html @@ -0,0 +1,971 @@ + + + + + + + + + *|MC:SUBJECT|* + + + + + + +
+ + + + +
+ + + + + + + + + + + +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + + +
+
+ +
+ + + + + +
+ + + + + +
+ + + + + + + + +
+ +

Authorization Request

+ +
+ + + +
+ + + + + +
+ + + + +
+ +
+ +
+ + + + + +
+ + + + + + + + +
+ +
+You are requested to authorize a document.

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

+ View Document +
+
+ + + + + +
+ + + + + + + + +
+ + Happy Blooming!
+Bloom Bot
+
+PS: This is an auto-generated email. If you'd like any technical support, please send an email to my humans - support@bloomstack.com +
+ + + +
+ + + + + +
+ + + + +
+ +
+ +
+ + + + + +
+ + + + +
+ +
+ +
+ +
+ + + + + +
+ + + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + + + + + + +
+ + + + +
+ + + + + + + +
+ +
+
+
+ + + + + + + + + + +
+ + + + +
+ + + + + + + +
+ +
+
+
+ + + + + + + + + + +
+ + + + +
+ + + + + + + +
+ +
+
+
+ + + + + + + + + + +
+ + + + +
+ + + + + + + +
+ +
+
+
+ + + + +
+
+
+ +
+ + + + + +
+ + + + +
+ +
+ +
+ + + + + +
+ + + + + + + + +
+ + Copyright ©2019 Bloomstack Inc, All rights reserved.
+
+Our mailing address is:
+support@bloomstack.com
+
+  +
+ + + +
+ +
+ +
+
+ + diff --git a/bloomstack_core/templates/includes/sign_document.js b/bloomstack_core/templates/includes/sign_document.js new file mode 100644 index 000000000..425a9d207 --- /dev/null +++ b/bloomstack_core/templates/includes/sign_document.js @@ -0,0 +1,43 @@ +$(document).ready(function () { + var $sigdiv = $("#signature"); + $sigdiv.jSignature(); // inits the jSignature widget. + $sigdiv.jSignature("reset"); // clears the canvas and rerenders the decor on it. + + $("#approveDocument").on("click", function () { + var sign = $sigdiv.jSignature("getData"); + var signee = $("#signee").val(); + if ($sigdiv.jSignature('getData', 'native').length != 0 && signee) { // proceed only if user has put signature and signee name. + $(".user-signature").hide(); + frappe.call({ + method: "bloomstack_core.utils.authorize_document", + args: { + sign: sign, + signee: signee, + docname: "{{ auth_req_docname }}", + }, + freeze: true, + callback: (r) => { + frappe.msgprint(__("The document has been approved by you!")); + } + }); + } + else { + + frappe.throw(__("Please put your name and signature!")); + } + }); + + $("#rejectDocument").on("click", function () { + $(".user-signature").hide(); + frappe.call({ + method: "bloomstack_core.utils.reject_document", + args: { + docname: "{{ auth_req_docname }}", + }, + freeze: true, + callback: (r) => { + frappe.msgprint(__("The document has been rejected by you!")); + } + }) + }); +}); \ No newline at end of file diff --git a/bloomstack_core/utils.py b/bloomstack_core/utils.py index d17ac3083..8f971af7b 100755 --- a/bloomstack_core/utils.py +++ b/bloomstack_core/utils.py @@ -78,3 +78,40 @@ def log_request(endpoint, request_data, response, ref_dt=None, ref_dn=None): }) request.insert() frappe.db.commit() + + +@frappe.whitelist(allow_guest=True) +def authorize_document(sign=None, signee=None, docname=None): + if frappe.db.exists("Authorization Request", docname): + authorization_request = frappe.get_doc("Authorization Request", docname) + authorization_request.signature = sign + authorization_request.signee_name = signee + authorization_request.status = "Approved" + authorization_request.flags.ignore_permissions = True + authorization_request.save() + + authorized_doc = frappe.get_doc(authorization_request.linked_doctype, authorization_request.linked_docname) + if hasattr(authorized_doc, "is_signed") and hasattr(authorized_doc, "authorizer_signature") and hasattr(authorized_doc, "signee"): + if authorized_doc.is_signed == 0: + authorized_doc.is_signed = 1 + authorized_doc.authorizer_signature = sign + authorized_doc.signee = signee + + authorized_doc.submit() + + +@frappe.whitelist(allow_guest=True) +def reject_document(docname): + if frappe.db.exists("Authorization Request", docname): + authorization_request = frappe.get_doc("Authorization Request", docname) + authorization_request.status = "Rejected" + authorization_request.save() + + +@frappe.whitelist() +def create_authorization_request(dt, dn, contact_email, contact_name=None): + new_authorization_request = frappe.new_doc("Authorization Request") + new_authorization_request.linked_doctype = dt + new_authorization_request.linked_docname = dn + new_authorization_request.authorizer_email = contact_email + new_authorization_request.save() \ No newline at end of file diff --git a/bloomstack_core/www/__init__.py b/bloomstack_core/www/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/bloomstack_core/www/authorize_document.html b/bloomstack_core/www/authorize_document.html new file mode 100644 index 000000000..fb85bea75 --- /dev/null +++ b/bloomstack_core/www/authorize_document.html @@ -0,0 +1,260 @@ +{% extends "templates/web.html" %} +{% block title %} Authorize Document {% endblock %} +{% block style %} + +{% endblock %} +{% block page_content %} +{% if error %} +{{ error }} +{% else %} +
+
+

{{company}} has requested you to authorize a {{doc.doctype}}


+
+
+ +
+
+ {{ print_doc }} +
+
+ +
+
+ Your Name:

+


+ Signature: +



+
+ Approve + Reject +
+
+ +
+{% endif %} +{% endblock %} + +{% block script %} + + +{% endblock %} \ No newline at end of file diff --git a/bloomstack_core/www/authorize_document.py b/bloomstack_core/www/authorize_document.py new file mode 100644 index 000000000..0a0c091af --- /dev/null +++ b/bloomstack_core/www/authorize_document.py @@ -0,0 +1,27 @@ +from __future__ import unicode_literals +from erpnext import get_default_company +import frappe +import re +no_cache = 1 + + +def get_context(context): + token = frappe.local.request.args.get("token") + docname = frappe.local.request.args.get("name") + auth_req = frappe.get_doc("Authorization Request", docname) + + if not token or token != auth_req.token: + context.error = "Token is not valid. Click here to re-send email" + + elif auth_req.status == "Approved": + context.error = "This document has already been authorized by you!" + + elif auth_req.status == "Rejected": + context.error = "This document has already been rejected by you!" + + frappe.local.flags.ignore_print_permissions = True + print_doc = frappe.get_print(auth_req.linked_doctype, auth_req.linked_docname) + context.print_doc = print_doc[print_doc.find('')+len(''):len(print_doc)-len('')] + context.doc = frappe.get_doc(auth_req.linked_doctype, auth_req.linked_docname) + context.company = context.doc.company if hasattr(context.doc, 'company') else get_default_company() + context.auth_req_docname = docname