You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

482 lines
17 KiB

[ADD] bond and loan issues management [ADD] bond and loan issues management module skeleton [IMP] change increase menu sequence [IMP] add models, fields and views [IMP] add xml declaration in head of file [ADD] add easy_my_coop_loan_website - WIP [IMP] add access rights [IMP] this raise inconsistency so replace id by default_code. [IMP] change import openerp to odoo [IMP] add website loan module [FIX] put website display in loan [FIX] fix import [FIX] fix function [IMP] use correct name [IMP] make the loan and bond visible [IMP] add js, field and logic to set amount limit per subscription [IMP] remove dependency on recaptcha as user is logged to subscribe [IMP] add fields [IMP] save loan issue subscription still in WIP [IMP] remove alert pop up [IMP] add dependency to easy_my_coop_website [IMP] remove force send for sub request creation email notification [IMP] add mail templates [IMP] save subscription in the corresponding loan issue. add email notif [FIX] fix loan issue line view [FIX] add related field to loan issue. It is where the data stand [IMP] move term_view up [FIX] fix js error when false is returned [FIX] fix function when loan_issue_id in None [IMP] add actions and button [FIX] fix action [FIX] fix mail template [IMP] set noupdate=1 [IMP] change order [IMP] display loan issue lines on partner form [IMP] add loan view in partner form [IMP] add face value on loan issue and line add face value on loan issue and line. add as well the quantity and computation of the amount [FIX] missing id overriding values wasn't working [IMP] getting bond face value and setting it as step. [IMP] subscribed_amount computed field is the sum of the amount lines [IMP] allow a waiting payment to be cancelled [IMP] make field required [REFACT] move loan issue line code to dedicated file [IMP] add interest calculation and model [ADD] bond and loan issues management module skeleton [IMP] add models, fields and views [IMP] allow creation by hand [IMP] adding partner related field [IMP] put code in separate function [FIX] pass it to get method [IMP] routes consistent form [FIX] fix eof [FIX] GET is working for ajax call [IMP] website page for loan issue subscription
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
[ADD] bond and loan issues management [ADD] bond and loan issues management module skeleton [IMP] change increase menu sequence [IMP] add models, fields and views [IMP] add xml declaration in head of file [ADD] add easy_my_coop_loan_website - WIP [IMP] add access rights [IMP] this raise inconsistency so replace id by default_code. [IMP] change import openerp to odoo [IMP] add website loan module [FIX] put website display in loan [FIX] fix import [FIX] fix function [IMP] use correct name [IMP] make the loan and bond visible [IMP] add js, field and logic to set amount limit per subscription [IMP] remove dependency on recaptcha as user is logged to subscribe [IMP] add fields [IMP] save loan issue subscription still in WIP [IMP] remove alert pop up [IMP] add dependency to easy_my_coop_website [IMP] remove force send for sub request creation email notification [IMP] add mail templates [IMP] save subscription in the corresponding loan issue. add email notif [FIX] fix loan issue line view [FIX] add related field to loan issue. It is where the data stand [IMP] move term_view up [FIX] fix js error when false is returned [FIX] fix function when loan_issue_id in None [IMP] add actions and button [FIX] fix action [FIX] fix mail template [IMP] set noupdate=1 [IMP] change order [IMP] display loan issue lines on partner form [IMP] add loan view in partner form [IMP] add face value on loan issue and line add face value on loan issue and line. add as well the quantity and computation of the amount [FIX] missing id overriding values wasn't working [IMP] getting bond face value and setting it as step. [IMP] subscribed_amount computed field is the sum of the amount lines [IMP] allow a waiting payment to be cancelled [IMP] make field required [REFACT] move loan issue line code to dedicated file [IMP] add interest calculation and model [ADD] bond and loan issues management module skeleton [IMP] add models, fields and views [IMP] allow creation by hand [IMP] adding partner related field [IMP] put code in separate function [FIX] pass it to get method [IMP] routes consistent form [FIX] fix eof [FIX] GET is working for ajax call [IMP] website page for loan issue subscription
5 years ago
5 years ago
5 years ago
  1. import base64
  2. import re
  3. from datetime import datetime
  4. from odoo import http
  5. from odoo.http import request
  6. from odoo.tools.translate import _
  7. # Only use for behavior, don't stock it
  8. _TECHNICAL = ["view_from", "view_callback"]
  9. # Allow in description
  10. _BLACKLIST = [
  11. "id",
  12. "create_uid",
  13. "create_date",
  14. "write_uid",
  15. "write_date",
  16. "user_id",
  17. "active",
  18. ]
  19. _COOP_FORM_FIELD = [
  20. "email",
  21. "confirm_email",
  22. "firstname",
  23. "lastname",
  24. "birthdate",
  25. "iban",
  26. "share_product_id",
  27. "address",
  28. "city",
  29. "zip_code",
  30. "country_id",
  31. "phone",
  32. "lang",
  33. "nb_parts",
  34. "total_parts",
  35. "error_msg",
  36. ]
  37. _COMPANY_FORM_FIELD = [
  38. "is_company",
  39. "company_register_number",
  40. "company_name",
  41. "company_email",
  42. "confirm_email",
  43. "email",
  44. "firstname",
  45. "lastname",
  46. "birthdate",
  47. "iban",
  48. "share_product_id",
  49. "address",
  50. "city",
  51. "zip_code",
  52. "country_id",
  53. "phone",
  54. "lang",
  55. "nb_parts",
  56. "total_parts",
  57. "error_msg",
  58. "company_type",
  59. ]
  60. class WebsiteSubscription(http.Controller):
  61. @http.route(
  62. ["/page/become_cooperator", "/become_cooperator"],
  63. type="http",
  64. auth="public",
  65. website=True,
  66. )
  67. def display_become_cooperator_page(self, **kwargs):
  68. values = {}
  69. logged = False
  70. if request.env.user.login != "public":
  71. logged = True
  72. partner = request.env.user.partner_id
  73. if partner.is_company:
  74. return self.display_become_company_cooperator_page()
  75. values = self.fill_values(values, False, logged, True)
  76. for field in _COOP_FORM_FIELD:
  77. if kwargs.get(field):
  78. values[field] = kwargs.pop(field)
  79. values.update(kwargs=kwargs.items())
  80. return request.render("easy_my_coop_website.becomecooperator", values)
  81. @http.route(
  82. ["/page/become_company_cooperator", "/become_company_cooperator"],
  83. type="http",
  84. auth="public",
  85. website=True,
  86. )
  87. def display_become_company_cooperator_page(self, **kwargs):
  88. values = {}
  89. logged = False
  90. if request.env.user.login != "public":
  91. logged = True
  92. values = self.fill_values(values, True, logged, True)
  93. for field in _COMPANY_FORM_FIELD:
  94. if kwargs.get(field):
  95. values[field] = kwargs.pop(field)
  96. values.update(kwargs=kwargs.items())
  97. return request.render(
  98. "easy_my_coop_website.becomecompanycooperator", values
  99. )
  100. def preRenderThanks(self, values, kwargs):
  101. """ Allow to be overrided """
  102. return {"_values": values, "_kwargs": kwargs}
  103. def get_subscription_response(self, values, kwargs):
  104. values = self.preRenderThanks(values, kwargs)
  105. return request.render("easy_my_coop_website.cooperator_thanks", values)
  106. def get_date_string(self, birthdate):
  107. if birthdate:
  108. return datetime.strftime(birthdate, "%d/%m/%Y")
  109. return False
  110. def get_values_from_user(self, values, is_company):
  111. # the subscriber is connected
  112. if request.env.user.login != "public":
  113. values["logged"] = "on"
  114. partner = request.env.user.partner_id
  115. if partner.member or partner.old_member:
  116. values["already_cooperator"] = "on"
  117. if partner.bank_ids:
  118. values["iban"] = partner.bank_ids[0].acc_number
  119. values["address"] = partner.street
  120. values["zip_code"] = partner.zip
  121. values["city"] = partner.city
  122. values["country_id"] = partner.country_id.id
  123. if is_company:
  124. # company values
  125. values[
  126. "company_register_number"
  127. ] = partner.company_register_number
  128. values["company_name"] = partner.name
  129. values["company_email"] = partner.email
  130. values["company_type"] = partner.legal_form
  131. # contact person values
  132. representative = partner.get_representative()
  133. values["firstname"] = representative.firstname
  134. values["lastname"] = representative.lastname
  135. values["gender"] = representative.gender
  136. values["email"] = representative.email
  137. values["contact_person_function"] = representative.function
  138. values["birthdate"] = self.get_date_string(
  139. representative.birthdate_date
  140. )
  141. values["lang"] = representative.lang
  142. values["phone"] = representative.phone
  143. else:
  144. values["firstname"] = partner.firstname
  145. values["lastname"] = partner.lastname
  146. values["email"] = partner.email
  147. values["gender"] = partner.gender
  148. values["birthdate"] = self.get_date_string(
  149. partner.birthdate_date
  150. )
  151. values["lang"] = partner.lang
  152. values["phone"] = partner.phone
  153. return values
  154. def fill_values(self, values, is_company, logged, load_from_user=False):
  155. sub_req_obj = request.env["subscription.request"]
  156. company = request.website.company_id
  157. products = self.get_products_share(is_company)
  158. if load_from_user:
  159. values = self.get_values_from_user(values, is_company)
  160. if is_company:
  161. values["is_company"] = "on"
  162. if logged:
  163. values["logged"] = "on"
  164. values["countries"] = self.get_countries()
  165. values["langs"] = self.get_langs()
  166. values["products"] = products
  167. fields_desc = sub_req_obj.sudo().fields_get(["company_type", "gender"])
  168. values["company_types"] = fields_desc["company_type"]["selection"]
  169. values["genders"] = fields_desc["gender"]["selection"]
  170. values["company"] = company
  171. if not values.get("share_product_id"):
  172. for product in products:
  173. if product.default_share_product is True:
  174. values["share_product_id"] = product.id
  175. break
  176. if not values.get("share_product_id", False) and products:
  177. values["share_product_id"] = products[0].id
  178. if not values.get("country_id"):
  179. if company.default_country_id:
  180. values["country_id"] = company.default_country_id.id
  181. else:
  182. values["country_id"] = "20"
  183. if not values.get("activities_country_id"):
  184. if company.default_country_id:
  185. values["activities_country_id"] = company.default_country_id.id
  186. else:
  187. values["activities_country_id"] = "20"
  188. if not values.get("lang"):
  189. if company.default_lang_id:
  190. values["lang"] = company.default_lang_id.code
  191. comp = request.env["res.company"]._company_default_get()
  192. values.update(
  193. {
  194. "display_data_policy": comp.display_data_policy_approval,
  195. "data_policy_required": comp.data_policy_approval_required,
  196. "data_policy_text": comp.data_policy_approval_text,
  197. "display_internal_rules": comp.display_internal_rules_approval,
  198. "internal_rules_required": comp.internal_rules_approval_required,
  199. "internal_rules_text": comp.internal_rules_approval_text,
  200. "display_financial_risk": comp.display_financial_risk_approval,
  201. "financial_risk_required": comp.financial_risk_approval_required,
  202. "financial_risk_text": comp.financial_risk_approval_text,
  203. }
  204. )
  205. return values
  206. def get_products_share(self, is_company):
  207. product_obj = request.env["product.template"]
  208. products = product_obj.sudo().get_web_share_products(is_company)
  209. return products
  210. def get_countries(self):
  211. countries = request.env["res.country"].sudo().search([])
  212. return countries
  213. def get_langs(self):
  214. langs = request.env["res.lang"].sudo().search([])
  215. return langs
  216. def get_selected_share(self, kwargs):
  217. prod_obj = request.env["product.template"]
  218. product_id = kwargs.get("share_product_id")
  219. return prod_obj.sudo().browse(int(product_id)).product_variant_ids[0]
  220. def validation( # noqa: C901 (method too complex)
  221. self, kwargs, logged, values, post_file
  222. ):
  223. user_obj = request.env["res.users"]
  224. sub_req_obj = request.env["subscription.request"]
  225. redirect = "easy_my_coop_website.becomecooperator"
  226. email = kwargs.get("email")
  227. is_company = kwargs.get("is_company") == "on"
  228. if is_company:
  229. is_company = True
  230. redirect = "easy_my_coop_website.becomecompanycooperator"
  231. email = kwargs.get("company_email")
  232. # TODO: Use a overloaded function with the captcha implementation
  233. if request.website.company_id.captcha_type == "google":
  234. if (
  235. "g-recaptcha-response" not in kwargs
  236. or kwargs["g-recaptcha-response"] == ""
  237. ):
  238. values = self.fill_values(values, is_company, logged)
  239. values.update(kwargs)
  240. values["error_msg"] = _(
  241. "the captcha has not been validated,"
  242. " please fill in the captcha"
  243. )
  244. return request.render(redirect, values)
  245. elif not request.website.is_captcha_valid(
  246. kwargs["g-recaptcha-response"]
  247. ):
  248. values = self.fill_values(values, is_company, logged)
  249. values.update(kwargs)
  250. values["error_msg"] = _(
  251. "the captcha has not been validated,"
  252. " please fill in the captcha"
  253. )
  254. return request.render(redirect, values)
  255. # Check that required field from model subscription_request exists
  256. required_fields = sub_req_obj.sudo().get_required_field()
  257. error = {
  258. field for field in required_fields if not values.get(field)
  259. } # noqa
  260. if error:
  261. values = self.fill_values(values, is_company, logged)
  262. values["error_msg"] = _(
  263. "Some mandatory fields have not " "been filled"
  264. )
  265. values = dict(values, error=error, kwargs=kwargs.items())
  266. return request.render(redirect, values)
  267. if not logged and email:
  268. user = user_obj.sudo().search([("login", "=", email)])
  269. if user:
  270. values = self.fill_values(values, is_company, logged)
  271. values.update(kwargs)
  272. values["error_msg"] = _(
  273. "There is an existing account for this"
  274. " mail address. Please login before "
  275. "fill in the form"
  276. )
  277. return request.render(redirect, values)
  278. else:
  279. confirm_email = kwargs.get("confirm_email")
  280. if email != confirm_email:
  281. values = self.fill_values(values, is_company, logged)
  282. values.update(kwargs)
  283. values["error_msg"] = _(
  284. "The email and the confirmation "
  285. "email doesn't match.Please check "
  286. "the given mail addresses"
  287. )
  288. return request.render(redirect, values)
  289. company = request.website.company_id
  290. if company.allow_id_card_upload:
  291. if not post_file:
  292. values = self.fill_values(values, is_company, logged)
  293. values.update(kwargs)
  294. values["error_msg"] = _(
  295. "You need to upload a" " scan of your id card"
  296. )
  297. return request.render(redirect, values)
  298. iban = kwargs.get("iban")
  299. if iban.strip():
  300. valid = sub_req_obj.check_iban(iban)
  301. if not valid:
  302. values = self.fill_values(values, is_company, logged)
  303. values["error_msg"] = _("You iban account number is not valid")
  304. return request.render(redirect, values)
  305. # check the subscription's amount
  306. max_amount = company.subscription_maximum_amount
  307. if logged:
  308. partner = request.env.user.partner_id
  309. if partner.member:
  310. max_amount = max_amount - partner.total_value
  311. if company.unmix_share_type:
  312. share = self.get_selected_share(kwargs)
  313. if partner.cooperator_type != share.default_code:
  314. values = self.fill_values(values, is_company, logged)
  315. values["error_msg"] = _(
  316. "You can't subscribe two "
  317. "different types of share"
  318. )
  319. return request.render(redirect, values)
  320. total_amount = float(kwargs.get("total_parts"))
  321. if max_amount > 0 and total_amount > max_amount:
  322. values = self.fill_values(values, is_company, logged)
  323. values["error_msg"] = (
  324. _("You can't subscribe for an amount that " "exceed ")
  325. + str(max_amount)
  326. + company.currency_id.symbol
  327. )
  328. return request.render(redirect, values)
  329. return True
  330. @http.route(
  331. ["/subscription/get_share_product"],
  332. type="json",
  333. auth="public",
  334. methods=["POST"],
  335. website=True,
  336. )
  337. def get_share_product(self, share_product_id, **kw):
  338. product_template = request.env["product.template"]
  339. product = product_template.sudo().browse(int(share_product_id))
  340. return {
  341. product.id: {
  342. "list_price": product.list_price,
  343. "min_qty": product.minimum_quantity,
  344. "force_min_qty": product.force_min_qty,
  345. }
  346. }
  347. @http.route(
  348. ["/subscription/subscribe_share"],
  349. type="http",
  350. auth="public",
  351. website=True,
  352. )
  353. def share_subscription(self, **kwargs):
  354. sub_req_obj = request.env["subscription.request"]
  355. attach_obj = request.env["ir.attachment"]
  356. # List of file to add to ir_attachment once we have the ID
  357. post_file = []
  358. # Info to add after the message
  359. post_description = []
  360. values = {}
  361. for field_name, field_value in kwargs.items():
  362. if hasattr(field_value, "filename"):
  363. post_file.append(field_value)
  364. elif (
  365. field_name in sub_req_obj._fields
  366. and field_name not in _BLACKLIST
  367. ):
  368. values[field_name] = field_value
  369. # allow to add some free fields or blacklisted field like ID
  370. elif field_name not in _TECHNICAL:
  371. post_description.append(
  372. "{}: {}".format(field_name, field_value)
  373. )
  374. logged = kwargs.get("logged") == "on"
  375. is_company = kwargs.get("is_company") == "on"
  376. response = self.validation(kwargs, logged, values, post_file)
  377. if response is not True:
  378. return response
  379. already_coop = False
  380. if logged:
  381. partner = request.env.user.partner_id
  382. values["partner_id"] = partner.id
  383. already_coop = partner.member
  384. elif kwargs.get("already_cooperator") == "on":
  385. already_coop = True
  386. values["already_cooperator"] = already_coop
  387. values["is_company"] = is_company
  388. if kwargs.get("data_policy_approved", "off") == "on":
  389. values["data_policy_approved"] = True
  390. if kwargs.get("internal_rules_approved", "off") == "on":
  391. values["internal_rules_approved"] = True
  392. if kwargs.get("financial_risk_approved", "off") == "on":
  393. values["financial_risk_approved"] = True
  394. lastname = kwargs.get("lastname").upper()
  395. firstname = kwargs.get("firstname").title()
  396. values["name"] = firstname + " " + lastname
  397. values["lastname"] = lastname
  398. values["firstname"] = firstname
  399. values["birthdate"] = datetime.strptime(
  400. kwargs.get("birthdate"), "%d/%m/%Y"
  401. ).date()
  402. values["source"] = "website"
  403. values["share_product_id"] = self.get_selected_share(kwargs).id
  404. if is_company:
  405. if kwargs.get("company_register_number", is_company):
  406. values["company_register_number"] = re.sub(
  407. "[^0-9a-zA-Z]+", "", kwargs.get("company_register_number")
  408. )
  409. subscription_id = sub_req_obj.sudo().create_comp_sub_req(values)
  410. else:
  411. subscription_id = sub_req_obj.sudo().create(values)
  412. if subscription_id:
  413. for field_value in post_file:
  414. attachment_value = {
  415. "name": field_value.filename,
  416. "res_name": field_value.filename,
  417. "res_model": "subscription.request",
  418. "res_id": subscription_id,
  419. "datas": base64.encodestring(field_value.read()),
  420. "datas_fname": field_value.filename,
  421. }
  422. attach_obj.sudo().create(attachment_value)
  423. return self.get_subscription_response(values, kwargs)