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.

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