mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[IMP] add commissions on reservation and folio
This commit is contained in:
@@ -37,19 +37,19 @@
|
||||
<!-- pms.sale.channel-->
|
||||
<record id="main_pms_sale_channel_0" model="pms.sale.channel">
|
||||
<field name="name">Door</field>
|
||||
<field name="channel_type">Direct</field>
|
||||
<field name="channel_type">direct</field>
|
||||
</record>
|
||||
<record id="main_pms_sale_channel_1" model="pms.sale.channel">
|
||||
<field name="name">Phone</field>
|
||||
<field name="channel_type">Direct</field>
|
||||
<field name="channel_type">direct</field>
|
||||
</record>
|
||||
<record id="main_pms_sale_channel_2" model="pms.sale.channel">
|
||||
<field name="name">Mail</field>
|
||||
<field name="channel_type">Direct</field>
|
||||
<field name="channel_type">direct</field>
|
||||
</record>
|
||||
<record id="main_pms_sale_channel_3" model="pms.sale.channel">
|
||||
<field name="name">Agency</field>
|
||||
<field name="channel_type">Indirect</field>
|
||||
<field name="channel_type">indirect</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -50,7 +50,9 @@ class PmsFolio(models.Model):
|
||||
pms_property_id = fields.Many2one(
|
||||
"pms.property", default=_get_default_pms_property, required=True
|
||||
)
|
||||
partner_id = fields.Many2one("res.partner", tracking=True, ondelete="restrict")
|
||||
partner_id = fields.Many2one(
|
||||
"res.partner", compute="_compute_partner_id", tracking=True, ondelete="restrict"
|
||||
)
|
||||
reservation_ids = fields.One2many(
|
||||
"pms.reservation",
|
||||
"folio_id",
|
||||
@@ -102,6 +104,13 @@ class PmsFolio(models.Model):
|
||||
readonly=False,
|
||||
help="Pricelist for current folio.",
|
||||
)
|
||||
commission = fields.Float(
|
||||
string="Commission",
|
||||
compute="_compute_commission",
|
||||
store=True,
|
||||
readonly=True,
|
||||
default=0,
|
||||
)
|
||||
user_id = fields.Many2one(
|
||||
"res.users",
|
||||
string="Salesperson",
|
||||
@@ -282,17 +291,26 @@ class PmsFolio(models.Model):
|
||||
folio.reservation_ids.filtered(lambda a: a.state != "cancelled")
|
||||
)
|
||||
|
||||
@api.depends("partner_id")
|
||||
@api.depends("partner_id", "agency_id")
|
||||
def _compute_pricelist_id(self):
|
||||
for folio in self:
|
||||
pricelist_id = (
|
||||
folio.partner_id.property_product_pricelist
|
||||
and folio.partner_id.property_product_pricelist.id
|
||||
or self.env.user.pms_property_id.default_pricelist_id.id
|
||||
)
|
||||
if folio.partner_id and folio.partner_id.property_product_pricelist:
|
||||
pricelist_id = folio.partner_id.property_product_pricelist.id
|
||||
else:
|
||||
pricelist_id = self.env.user.pms_property_id.default_pricelist_id.id
|
||||
if folio.pricelist_id.id != pricelist_id:
|
||||
# TODO: Warning change de pricelist?
|
||||
folio.pricelist_id = pricelist_id
|
||||
if folio.agency_id and folio.agency_id.apply_pricelist:
|
||||
pricelist_id = folio.agency_id.property_product_pricelist.id
|
||||
|
||||
@api.depends("agency_id")
|
||||
def _compute_partner_id(self):
|
||||
for folio in self:
|
||||
if folio.agency_id and folio.agency_id.invoice_agency:
|
||||
folio.partner_id = folio.agency_id.id
|
||||
elif not folio.partner_id:
|
||||
folio.partner_id = False
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_user_id(self):
|
||||
@@ -311,11 +329,20 @@ class PmsFolio(models.Model):
|
||||
self.payment_term_id = False
|
||||
for folio in self:
|
||||
folio.payment_term_id = (
|
||||
self.partner_id.property_payment_term_id
|
||||
and self.partner_id.property_payment_term_id.id
|
||||
folio.partner_id.property_payment_term_id
|
||||
and folio.partner_id.property_payment_term_id.id
|
||||
or False
|
||||
)
|
||||
|
||||
@api.depends("reservation_ids")
|
||||
def _compute_commission(self):
|
||||
for folio in self:
|
||||
for reservation in folio.reservation_ids:
|
||||
if reservation.commission_amount != 0:
|
||||
folio.commission += reservation.commission_amount
|
||||
else:
|
||||
folio.commission = 0
|
||||
|
||||
@api.depends(
|
||||
"state", "reservation_ids.invoice_status", "service_ids.invoice_status"
|
||||
)
|
||||
|
||||
@@ -192,6 +192,17 @@ class PmsReservation(models.Model):
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
commission_percent = fields.Float(
|
||||
string="Commission percent (%)",
|
||||
compute="_compute_commission_percent",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
commission_amount = fields.Float(
|
||||
string="Commission amount",
|
||||
compute="_compute_commission_amount",
|
||||
store=True,
|
||||
)
|
||||
# TODO: Warning Mens to update pricelist
|
||||
checkin_partner_ids = fields.One2many("pms.checkin.partner", "reservation_id")
|
||||
segmentation_ids = fields.Many2many(
|
||||
@@ -438,7 +449,7 @@ class PmsReservation(models.Model):
|
||||
)
|
||||
reservation.allowed_room_ids = rooms_available
|
||||
|
||||
@api.depends("reservation_type")
|
||||
@api.depends("reservation_type", "agency_id")
|
||||
def _compute_partner_id(self):
|
||||
for reservation in self:
|
||||
if reservation.reservation_type == "out":
|
||||
@@ -447,6 +458,8 @@ class PmsReservation(models.Model):
|
||||
reservation.partner_id = reservation.folio_id.partner_id
|
||||
else:
|
||||
reservation.partner_id = False
|
||||
if not reservation.partner_id and reservation.agency_id:
|
||||
reservation.partner_id = reservation.agency_id
|
||||
|
||||
@api.depends("partner_id")
|
||||
def _compute_partner_invoice_id(self):
|
||||
@@ -525,6 +538,26 @@ class PmsReservation(models.Model):
|
||||
# TODO: Warning change de pricelist?
|
||||
reservation.pricelist_id = pricelist_id
|
||||
|
||||
@api.depends("agency_id")
|
||||
def _compute_commission_percent(self):
|
||||
for reservation in self:
|
||||
if reservation.agency_id:
|
||||
reservation.commission_percent = (
|
||||
reservation.agency_id.default_commission
|
||||
)
|
||||
else:
|
||||
reservation.commission_percent = 0
|
||||
|
||||
@api.depends("commission_percent", "price_total")
|
||||
def _compute_commission_amount(self):
|
||||
for reservation in self:
|
||||
if reservation.commission_percent > 0:
|
||||
reservation.commission_amount = (
|
||||
reservation.price_total * reservation.commission_percent
|
||||
)
|
||||
else:
|
||||
reservation.commission_amount = 0
|
||||
|
||||
# REVIEW: Dont run with set room_type_id -> room_id(compute)-> No set adults¿?
|
||||
@api.depends("preferred_room_id")
|
||||
def _compute_adults(self):
|
||||
@@ -824,21 +857,11 @@ class PmsReservation(models.Model):
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if "folio_id" in vals and "channel_type_id" not in vals:
|
||||
if "folio_id" in vals:
|
||||
folio = self.env["pms.folio"].browse(vals["folio_id"])
|
||||
channel_type_id = (
|
||||
vals["channel_type_id"]
|
||||
if "channel_type_id" in vals
|
||||
else folio.channel_type_id
|
||||
)
|
||||
partner_id = (
|
||||
vals["partner_id"] if "partner_id" in vals else folio.partner_id.id
|
||||
)
|
||||
vals.update({"channel_type_id": channel_type_id, "partner_id": partner_id})
|
||||
elif "partner_id" in vals:
|
||||
folio_vals = {
|
||||
"partner_id": int(vals.get("partner_id")),
|
||||
"channel_type_id": vals.get("channel_type_id"),
|
||||
}
|
||||
# Create the folio in case of need
|
||||
# (To allow to create reservations direct)
|
||||
@@ -847,7 +870,6 @@ class PmsReservation(models.Model):
|
||||
{
|
||||
"folio_id": folio.id,
|
||||
"reservation_type": vals.get("reservation_type"),
|
||||
"channel_type_id": vals.get("channel_type_id"),
|
||||
}
|
||||
)
|
||||
record = super(PmsReservation, self).create(vals)
|
||||
|
||||
@@ -27,6 +27,9 @@ class ResPartner(models.Model):
|
||||
ondelete="restrict",
|
||||
domain=[("channel_type", "=", "indirect")],
|
||||
)
|
||||
default_commission = fields.Integer("Commission")
|
||||
apply_pricelist = fields.Boolean("Apply Pricelist")
|
||||
invoice_agency = fields.Boolean("Invoice Agency")
|
||||
|
||||
# Compute and Search methods
|
||||
def _compute_reservations_count(self):
|
||||
|
||||
@@ -22,3 +22,4 @@
|
||||
from . import test_pms_reservation
|
||||
from . import test_pms_pricelist
|
||||
from . import test_pms_sale_channel
|
||||
from . import test_pms_folio
|
||||
|
||||
58
pms/tests/test_pms_folio.py
Normal file
58
pms/tests/test_pms_folio.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import datetime
|
||||
|
||||
from freezegun import freeze_time
|
||||
|
||||
from .common import TestHotel
|
||||
|
||||
freeze_time("2000-02-02")
|
||||
|
||||
|
||||
class TestPmsFolio(TestHotel):
|
||||
def test_commission_and_partner_correct(self):
|
||||
# ARRANGE
|
||||
PmsFolio = self.env["pms.folio"]
|
||||
PmsReservation = self.env["pms.reservation"]
|
||||
PmsPartner = self.env["res.partner"]
|
||||
PmsSaleChannel = self.env["pms.sale.channel"]
|
||||
# ACT
|
||||
saleChannel = PmsSaleChannel.create(
|
||||
{"name": "saleChannel1", "channel_type": "indirect"}
|
||||
)
|
||||
agency = PmsPartner.create(
|
||||
{
|
||||
"name": "partner1",
|
||||
"is_agency": True,
|
||||
"invoice_agency": True,
|
||||
"default_commission": 15,
|
||||
"sale_channel_id": saleChannel.id,
|
||||
}
|
||||
)
|
||||
|
||||
reservation = PmsReservation.create(
|
||||
{
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"agency_id": agency.id,
|
||||
}
|
||||
)
|
||||
folio = PmsFolio.create(
|
||||
{
|
||||
"agency_id": agency.id,
|
||||
"reservation_ids": [reservation.id],
|
||||
}
|
||||
)
|
||||
|
||||
commission = 0
|
||||
for reservation in folio:
|
||||
commission += reservation.commission_amount
|
||||
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
folio.commission,
|
||||
commission,
|
||||
"Folio commission don't math with his reservation commission",
|
||||
)
|
||||
if folio.agency_id:
|
||||
self.assertEqual(
|
||||
folio.agency_id, folio.partner_id, "Agency has to be the partner"
|
||||
)
|
||||
@@ -243,19 +243,6 @@
|
||||
'readonly': [('partner_id', '!=', False),
|
||||
('mobile','!=', False)]}"
|
||||
/>
|
||||
<!--<field
|
||||
name="phone"
|
||||
colspan="2"
|
||||
nolabel="1"
|
||||
placeholder="phone"
|
||||
widget="phone"
|
||||
force_save="1"
|
||||
attrs="{'invisible': [('reservation_type','in',('out'))],
|
||||
'required': [('channel_type','in',('door','mail','phone')),
|
||||
('mobile','=','')],
|
||||
'readonly': [('partner_id', '!=', False),
|
||||
('phone','!=', False)]}"
|
||||
/>-->
|
||||
<field
|
||||
placeholder="Partner Notes"
|
||||
colspan="2"
|
||||
@@ -370,6 +357,17 @@
|
||||
string="Only Room"
|
||||
widget="monetary"
|
||||
/>
|
||||
<field
|
||||
name="commission_percent"
|
||||
string="Commission percent (%)"
|
||||
>
|
||||
<field
|
||||
name="commission_amount"
|
||||
string="Commission Amount"
|
||||
>
|
||||
|
||||
</field>
|
||||
</field>
|
||||
<field name="invoice_status" invisible="1" />
|
||||
<field name="currency_id" invisible="1" />
|
||||
<field
|
||||
|
||||
@@ -39,13 +39,30 @@
|
||||
<field string="Folios" name="folios_count" widget="statinfo" />
|
||||
</button>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='vat']" position="after">
|
||||
<xpath expr="//field[@name='name']" position="after">
|
||||
<field name="is_agency" />
|
||||
<field
|
||||
name="sale_channel_id"
|
||||
</xpath>
|
||||
<xpath expr="//page[@name='internal_notes']" position="after">
|
||||
<page
|
||||
name="agency"
|
||||
string="Agency"
|
||||
attrs="{'invisible':[('is_agency','!=',True)]}"
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
/>
|
||||
>
|
||||
<group>
|
||||
<field
|
||||
name="sale_channel_id"
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
/>
|
||||
<field name="default_commission" />
|
||||
<!-- <label for="price_discount"/>
|
||||
<div class="o_row">
|
||||
<field name="price_discount"/>
|
||||
<span>%%</span>
|
||||
</div>-->
|
||||
<field name="apply_pricelist" />
|
||||
<field name="invoice_agency" />
|
||||
</group>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
Reference in New Issue
Block a user