How to calculate number of nights for hotel management module in Odoo 8 - odoo-8

I am working on hotel management module in odoo version 8.
I wish to calculate number of nights stayed between check-in date and check-out date. Can anyone help me with this?
I defined a class for reservations, with on change methods for check-in and check-out. I tried for a function calculating total_nights. Here is my code,
class hotel_reservation(osv.Model):
_name = "hotel.reservation"
_rec_name = "reservation_no"
_description = "Reservation"
_order = 'reservation_no desc'
_columns = {
'reservation_no': fields.char('Reservation No', size=64, required=True, readonly=True),
'date_order':fields.datetime('Date Ordered', required=True, readonly=True, states={'draft':[('readonly', False)]}),
'warehouse_id':fields.many2one('stock.warehouse', 'Hotel', readonly=True, required=True, states={'draft':[('readonly', False)]}),
'partner_id':fields.many2one('res.partner', 'Guest Name', readonly=True, required=True, states={'draft':[('readonly', False)]}),
'pricelist_id':fields.many2one('product.pricelist', 'Price List', required=True, readonly=True, states={'draft':[('readonly', False)]}, help="Pricelist for current reservation. "),
'partner_invoice_id':fields.many2one('res.partner', 'Invoice Address', readonly=True, states={'draft':[('readonly', False)]}, help="Invoice address for current reservation. "),
'partner_order_id':fields.many2one('res.partner', 'Ordering Contact', readonly=True, states={'draft':[('readonly', False)]}, help="The name and address of the contact that requested the order or quotation."),
'partner_shipping_id':fields.many2one('res.partner', 'Delivery Address', readonly=True, states={'draft':[('readonly', False)]}, help="Delivery address for current reservation. "),
'checkin': fields.datetime('Expected-Date-Arrival', required=True, readonly=True, states={'draft':[('readonly', False)]}),
'checkout': fields.datetime('Expected-Date-Departure', required=True, readonly=True, states={'draft':[('readonly', False)]}),
'adults':fields.integer('Adults', size=64, readonly=True, states={'draft':[('readonly', False)]}, help='List of adults there in guest list. '),
'children':fields.integer('Children', size=64, readonly=True, states={'draft':[('readonly', False)]}, help='Number of children there in guest list. '),
'reservation_line':fields.one2many('hotel_reservation.line', 'line_id', 'Reservation Line', help='Hotel room reservation details. '),
'state': fields.selection([('draft', 'Draft'), ('confirm', 'Confirm'), ('cancel', 'Cancel'), ('done', 'Done')], 'State', readonly=True),
'folio_id': fields.many2many('hotel.folio', 'hotel_folio_reservation_rel', 'order_id', 'invoice_id', 'Folio'),
'dummy': fields.datetime('Dummy'),
#'No_of_nights': fields.integer('Number of Nights', size=64, readonly=True, states={'draft':[('readonly', False)]}, help='Number of Nights.'),
'no_of_nights':fields.function(_total_nights, string='Amount to be returned',
store={
'value': (lambda self, cr, uid, ids, c={}: ids, ['amount', 'roi'], 10),
},),
}
_defaults = {
'reservation_no': lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'hotel.reservation'),
'state': lambda *a: 'draft',
'date_order': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
}
def on_change_checkin(self, cr, uid, ids, date_order, checkin_date=time.strftime('%Y-%m-%d %H:%M:%S'), context=None):
if date_order and checkin_date:
if checkin_date < date_order:
raise osv.except_osv(_('Warning'), _('Checkin date should be greater than the current date.'))
return {'value':{}}
def on_change_checkout(self, cr, uid, ids, checkin_date=time.strftime('%Y-%m-%d %H:%M:%S'), checkout_date=time.strftime('%Y-%m-%d %H:%M:%S'), context=None):
if not (checkout_date and checkin_date):
return {'value':{}}
if checkout_date < checkin_date:
raise osv.except_osv(_('Warning'), _('Checkout date should be greater than the Checkin date.'))
delta = datetime.timedelta(days=1)
addDays = datetime.datetime(*time.strptime(checkout_date, '%Y-%m-%d %H:%M:%S')[:5]) + delta
val = {'value':{'dummy':addDays.strftime('%Y-%m-%d %H:%M:%S')}}
return val
def onchange_partner_id(self, cr, uid, ids, partner_id):
if not partner_id:
return {'value':{'partner_invoice_id': False, 'partner_shipping_id':False, 'partner_order_id':False}}
partner_obj = self.pool.get('res.partner')
addr = partner_obj.address_get(cr, uid, [partner_id], ['delivery', 'invoice', 'contact'])
pricelist = partner_obj.browse(cr, uid, partner_id).property_product_pricelist.id
return {'value':{'partner_invoice_id': addr['invoice'], 'partner_order_id':addr['contact'], 'partner_shipping_id':addr['delivery'], 'pricelist_id': pricelist}}
def total_nights(self, cr, uid, ids, context=None):
print("Function for Calculating total Nights !")
context = context or {}
res = {}
''''''
for value in self.browse(cr, uid, ids, checkin_date=time.strftime('%Y-%m-%d %H:%M:%S'), checkout_date=time.strftime('%Y-%m-%d %H:%M:%S'), context=context):
check_in = datetime.strptime(check_in, "%Y-%m-%d")
check_out = datetime.strptime(check_out, "%Y-%m-%d")
delta = check_out - check_in
print delta.days
return res
class hotel_room_reservation_line(osv.Model):
_name = 'hotel.room.reservation.line'
_description = 'Hotel Room Reservation'
_rec_name = 'room_id'
_columns = {
'room_id': fields.many2one('hotel.room', 'Room id'),
'check_in':fields.datetime('Check In Date', required=True),
'check_out': fields.datetime('Check Out Date', required=True),
'state': fields.selection([('assigned', 'Assigned'), ('unassigned', 'Unassigned')], 'Room Status'),
'reservation_id': fields.many2one('hotel.reservation', 'Reservation'),
}
hotel_room_reservation_line()

This code may help you:
# Making difference in dates to get no. of days .....
#api.one
#api.onchange('check_in')
def onchange_date_time(self):
# print 'working till now ----------------------------'
if self.check_in:
check_in = datetime.datetime.strptime(self.check_in, "%Y-%m-%d").date()
if check_in<datetime.date.today():
#raise except_orm('Error','Please enter the correct date')
self.check_in = None
else:
pass
#api.one
#api.onchange('check_out')
def onchange_check_out(self):
if self.check_out:
check_out = datetime.datetime.strptime(self.check_out, "%Y-%m-%d").date()
check_in = datetime.datetime.strptime(self.check_in, "%Y-%m-%d").date()
if check_out<datetime.date.today():
self.check_out = False
# if not self.check_out:
# raise osv.except_orm('Error','Please enter the correct date')
else:
pass
#api.onchange('check_out')
def onchange_num_day(self):
if self.check_out and self.check_in:
check_in = datetime.datetime.strptime(self.check_in, "%Y-%m-%d").date()
check_out = datetime.datetime.strptime(self.check_out, "%Y-%m-%d").date()
self.days = (check_out-check_in).days+1
if self.days == 0:
self.days = 1
#Hence we will get No.of days .. Ends
fields: checked_in,checked_out,days
Thanks

Related

Unable to create profile from user Serializer (Django-resst-framework)

I have 2 models, Account model as shown
class Account(AbstractBaseUser,PermissionsMixin):
email = models.EmailField(max_length=100, unique = True)
username = models.CharField(max_length = 30)
is_admin = models.BooleanField(default = False)
is_staff = models.BooleanField(default = False)
is_active = models.BooleanField(default = False)
date_joined = models.DateTimeField(auto_now_add = True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = [
'username'
]
and the profile table as shown below
class Profile(models.Model):
user = models.OneToOneField(Account, on_delete = models.CASCADE)
avatar = models.ImageField(default = "defaultpic.png", blank = True, null = True, upload_to="MEDIA_FILES" )
tel = PhoneField(blank=False, null = False)
ProfileSerializer
class ProfileSerializer(serializers.ModelSerializer):
class Meta:
model = Profile
fields = [
'avatar',
'tel',
]
UserSerializer
class AccountSerializer(serializers.ModelSerializer):
profile = ProfileSerializer(read_only = True)
class Meta:
model = get_user_model()
fields = [
'email',
'username',
'password',
'profile'
]
extra_kwargs = {
'password': {'write_only': True},
}
def create(self, validated_data):
user_password = validated_data.pop('password')
user = get_user_model()(
email = validated_data['email'],
username = validated_data['username']
)
user.set_password(user_password)
user.save()
user.email_user("Hello world")
return user
Endpoint to register a new user
#api_view(["POST"])
#permission_classes([AllowAny, ])
def register(request):
profSerializer = ProfileSerializer( data = request.data )
serializer = AccountSerializer( data = request.data )
if serializer.is_valid():
serializer.save()
serializer.send_mail("Hello")
return JsonResponse( serializer.data )
else:
print( serializer.errors )
return JsonResponse( { "_err": serializer.errors } )
My problem now comes in when I send a post request to the registering endpoint, the profile fields remain empty, the avatar field is assigned the default value of default.png. I need the endpoint to create both user account and profile entries whenever a user sign up
The post request to the endpoint is the following JSON
{
email:"some email",
username:"username",
password:"password",
tel:"tel number",
avatar:"image"
}
In your AccountSerializer you have set the profile field to read only:
profile = ProfileSerializer(read_only=True)
This means the field will be neglected and will not be shown in request.data.
Then you need a little change in your create method, something like this:
def create(self, validated_data):
profile_data = validated_data['profile']
# user creation steps
...
profile = Profile(
user=user,
**profile_data
)
profile.save()
return user
rest_framework cannot create related objects by default, this is why you need to create an account instance first, and then create a Profile by yourself
Then, you do not need to serialize request.data with ProfileSerializer in your view, remove the line and change the request body to:
{
email:"some email",
username:"username",
password:"password",
profile: {
tel:"tel number",
avatar:"image"
}
}
I suggest you learning about nested serializers and how they work

generate random username automatically in django rest

Is there any way to generate the username automatically. and I also need username while signing in so it must be unique-
class User(AbstractUser):
username = models.CharField(max_length=50, unique=True, null= False, blank=False)
email = models.EmailField(unique=True, null=False, blank=False)
USERNAME_FIELD = 'username'
def __str__(self):
return "{}".format(self.email)
below is the code for user create serializer:
class UserSerializer(serializers.HyperlinkedModelSerializer):
profile = UserProfileSerializer(required=True)
username = serializers.CharField(label="username field",
required=True, allow_null=False,
allow_blank=False)
class Meta:
model = User
fields = ('id', 'username', 'email', 'first_name', 'last_name', 'password', 'profile')
extra_kwargs = {'password': {'write_only': True}, 'first_name': {'required': True},
'last_name': {'required': True}}
def create(self, validated_data):
profile_data = validated_data.pop('profile')
password = validated_data.pop('password')
try:
if User.objects.filter(username__iexact=User(**validated_data).username).exists():
raise serializers.ValidationError("username already exists")
except Exception as e:
error = {'message': ",".join(e.args) if len(e.args) > 0 else 'Unknown Error'}
raise serializers.ValidationError(error)
user = User(**validated_data)
print(user.username)
user.set_password(password)
user.save()
UserProfile.objects.create(user=user, **profile_data)
return user
what changes should i make to generate username automatically?
You should raise ValidationError only from validate functions.
Use managers to create objects. User model has built-in create_user method.
To generate username you could use a library such as coolname.
Create two serializers. One for creating user and another one for reading.
If you want to allow users to specify their own username, add a validator on the field.
Move profile creation to create_user method.
from coolname import generate_slug
class UserCreateSerializer(serializers.HyperlinkedModelSerializer):
username = serializers.CharField(
min_length=3,
max_length=50,
validators=[UniqueValidator(queryset=User.objects.all())],
allow_null=True,
default=None
)
class Meta:
model = User
fields = ('username',)
def validate_username(self, val):
return val or generate_slug()
def perform_create(self, validated_data):
# use User manager
...
You can use this method: from allauth.utils import generate_unique_username
Then you can generate unique usernames like this:
# Create user object
first_name = 'My firstname'
last_name = 'My lastname'
email = 'myemail#gmail.com'
user = User()
user.first_name = first_name
user.last_name = last_name
user.email = email
user.username = generate_unique_username([f'{first_name} {last_name}', email, 'user'])
user.save()

How to get the nested objects in DRF

I have two models Role and User. User model has a foreign-key field associated with model Role.
Model Role
class Role(models.Model):
role_name = models.CharField(max_length=255, blank=False, unique=True)
def __str__(self):
return 'Role Object ({})'.format(self.id, self.role_name)
Model User
class User(AbstractBaseUser, PermissionsMixin):
first_name = models.CharField(max_length=255, blank=False)
last_name = models.CharField(max_length=255, blank=False)
email = models.EmailField(max_length=255, blank=False, unique= True)
phone_number = models.BigIntegerField(blank=False, unique= True)
password = models.TextField(blank=False)
company_name = models.CharField(max_length=255, null=True, unique=True)
is_active = models.BooleanField(default= False)
role = models.ForeignKey(Role, related_name='group_name', on_delete=models.CASCADE, blank=False)
business = models.ForeignKey(Businesses, on_delete=models.CASCADE, null=True)
objects = UserManager()
USERNAME_FIELD = 'email'
def __str__(self):
return 'User Object ({})'.format(self.id)
Using ModelSerializer and ListAPIView I want to get the list of all the users as shown below -
{
"first_name": "",
"last_name":"",
"email":"",
"phone_number":,
"is_active":"",
"role":{
"id":1,
"role_name": "Admin"
}
}
Also, I have created serializers -
class AdminSerializer(serializers.ModelSerializer):
role = RoleSerializer(read_only=True)
class Meta:
model = User
fields = ['id', 'first_name', 'last_name', 'email', 'phone_number', 'password', 'role', 'is_active' ]
read_only_field = ['role_name']
extra_kwargs = {
'password':{
'write_only':True
},
'is_active':{
'required':False
}
}
def create(self, validated_data):
return User.objects.create_user(**validated_data)
class RoleSerializer(serializers.ModelSerializer):
class Meta:
model = Role
field = ['id', 'role_name']
What exactly should I do to my serializer to achieve desire output. What exactly should I write in my ListAPIView() what a ListAPIVIew returns.
class UsersListAPIView(ListAPIView):
queryset = User.objects.all()
serializer_class = AdminSerializer
def list(self, request):
queryset = self.get_queryset().filter(role=request.query_params.get['id']).prefetch_related("group_name")
serializer = AdminSerializer(queryset, many=True)
return Response(serializer.data)
This returns an error -
TypeError: 'method' object is not subscriptable

Cannot Login using Custom User Model Django Rest Framework

I just create a Custom User Model with Django for Django Rest Framework,
I create the generics.ListAPIView to get the list of User and Create New User
Then I create the Login View with views.APIView with overridden post() with validation. But when I clicked the "POST", its return the "User already exists". Why the login method tried to create an account even when i use django-rest-auth?
Thanks in advance
here is the code
models.py
class AccountManager(BaseUserManager):
def create_user(self, email, first_name=None, last_name=None, password=None, is_active=True, is_staff=False, is_admin=False, is_superuser=False):
if not email:
raise ValueError("User must have an email address")
if not password:
raise ValueError("User must have a password")
if not first_name:
raise ValueError("User must have a first name")
user = self.model(
email=self.normalize_email(email)
)
user.set_password(password)
user.first_name = first_name
user.last_name = last_name
user.staff = is_staff
user.admin = is_admin
user.active = is_active
user.superuser = is_superuser
user.save(using=self._db)
return user
def create_superuser(self, email, first_name=None, last_name=None, password=None):
user = self.create_user(
email=email,
first_name = first_name,
last_name = last_name,
password=password,
is_superuser=True,
is_staff=True,
is_admin=True,
)
return user
class Account(AbstractBaseUser):
email =models.EmailField(max_length=255, unique=True)
first_name = models.CharField(max_length=255,default='')
last_name = models.CharField(max_length=255, default='')
active = models.BooleanField(default=True)
staff = models.BooleanField(default=False)
admin = models.BooleanField(default=False)
superuser = models.BooleanField(default=False)
created_data = models.DateTimeField(auto_now_add=True)
last_login = models.DateTimeField(auto_now=True)
#USERNAME_FIELD and password are required by default
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['first_name', 'last_name']
objects = AccountManager()
def __str__(self):
return self.email
def get_full_name(self):
return (self.first_name + self.last_name)
def get_short_name(self):
return self.first_name
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
#property
def is_admin(self):
return self.admin
#property
def is_staff(self):
return self.staff
#property
def is_superuser(self):
return self.superuser
serializers.py
class AccountRegistrationSerializer(serializers.ModelSerializer):
# password = serializers.CharField(style={'input_type':'password'}, write_only=True)
password2 = serializers.CharField(style={'input_type':'password'}, write_only=True)
class Meta:
model = Account
extra_kwargs = {
'password': {'write_only': True}
}
fields = ['email', 'first_name', 'last_name','password', 'password2',]
def create(self, validated_data):
account = Account(
email=self.validated_data['email'],
first_name=self.validated_data['first_name'],
last_name=self.validated_data['last_name']
)
password = self.validated_data['password']
password2 = self.validated_data['password2']
if password != password2:
raise serializer.ValidationError({'password':'Passwords must match'})
account.set_password(password)
account.save()
return account
class AccountLoginSerializer(serializers.ModelSerializer):
class Meta:
model = Account
extra_kwargs = {
'password': {
'write_only': True
},
'first_name': {
'read_only': True
},
'last_name': {
'read_only': True
},
}
fields = ['email', 'first_name', 'last_name', 'password']
def validate(self, data):
return data
views.py
class AccountLoginView(APIView):
permission_classes = [AllowAny,]
serializer_class = AccountLoginSerializer
def post(self, request, *args, **kwargs):
data = request.data
serializer = AccountLoginSerializer(data=data)
if serializer.is_valid(raise_exception=True):
new_data = serializer.data
return Response(new_data, status=HTTP_200_OK)
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
it's been 5 days since I asked this question.
I have solved this problem by override to_internal_value method and validate the serializers.
serializer.py
def to_internal_value(self, data):
try:
try:
email = data["email"]
user = Account.objects.filter(email=email)
return data
except KeyError:
raise serializers.ValidationError({'email':'Please Input your Email'})
except ValueError:
raise serializers.ValidationError({'email':'Email Not Valid'})
except Account.DoesNotExist:
raise serializers.ValidationError({'error':'Database Error'})
def validate(self, data):
user_obj=None
email = data.get('email', None)
password = data.get('password', None)
if not email and not username:
raise ValidationError({"error":"Need to be filled"})
user = Account.objects.filter(
Q(email=email)
).distinct()
user = user.exclude(email__isnull=True).exclude(email__iexact='')
if user.exists() and user.count() == 1:
user_obj = user.first()
else:
raise ValidationError({"email":"Not valid"})
if user_obj:
if not user_obj.check_password(password):
raise ValidationError({"password":"Incorrect credentials please try again"})
new_data = user_obj
return new_data

Create model with foreign key and return serialized response

I'm trying to create a new note via a POST request that looks like this: {content: "hello world", user: 1} with a response that looks like this: { id: 1, content: "hello world", user: { id: 1, first_name: "Homer", last_name: "Simpson" }.
After reading at the other foreign key questions I've been able to create the note and get back something like: { id: 1, content: "hello world", user: 1 } but I really need the additional user information.
I attempted to modify the response using the to_representation like so:
class NotePOSTSerializer(serializers.ModelSerializer):
class Meta:
model = Note
fields = ('id', 'content', 'timestamp', 'user')
def to_representation(self, instance):
rep = super().to_representation(instance)
"""Convert `status` to human-readable."""
rep['user'] = UserSerializer(id=rep['user'])
return rep
but I got this error: TypeError: Object of type ModelState is not JSON serializable
This is what I've got so far. Thanks in advance!
models.py
class Article(models.Model):
id = models.PositiveSmallIntegerField('Article Id', null=True)
title = models.CharField('Title', max_length=100)
content = models.TextField('Description', blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
class Note(models.Model):
id = models.PositiveSmallIntegerField('Note Id', null=True)
content = models.TextField('Content', blank=True)
timestamp = models.DateTimeField('Timestamp', auto_now_add=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
views.py
class ArticleListView(viewsets.ModelViewSet):
serializer_class = ArticleSerializer
queryset = Article.objects.all()
class NoteListView(viewsets.ModelViewSet):
serializer_class =NoteSerializer
queryset = Note.objects.all()
def get_serializer_class(self):
assert self.serializer_class is not None, (
"'%s' should either include a `serializer_class` attribute, "
"or override the `get_serializer_class()` method."
% self.__class__.__name__
)
if self.request.method in ('POST', 'PUT'):
return NotePOSTSerializer
else:
return self.serializer_class
serializers.py
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ('id', 'username', 'first_name', 'last_name', 'email')
class NoteSerializer(serializers.ModelSerializer):
user = UserSerializer()
class Meta:
model = Note
fields = ('id', 'content', 'timestamp', 'user')
class NotePOSTSerializer(serializers.ModelSerializer):
class Meta:
model = Note
fields = ('id', 'content', 'timestamp', 'user')
class ArticleSerializer(serializers.ModelSerializer):
notes = NoteSerializer(many=True, read_only=True)
class Meta:
model = Article
fields = ('id', 'title', 'content', 'created', 'updated', 'notes')
I'm getting completely different errors, so I will just provide working code
def to_representation(self, instance):
rep = super().to_representation(instance)
rep['user'] = UserSerializer(instance=User.objects.get(pk=instance.user_id)).data
# UserSerializer(instance=instance)
return rep

Resources