How to Show Date into words in odoo 12 reports - python

I am using odoo 12 and want to show Date field record from a model into Reports, how can i do this?
Still facing error
time data 'False' does not match format '%d %B, %Y'
here is my code
#api.multi
def _get_student_dob_in_words(self, student_id):
date_of_birth = fields.Date('BirthDate', default=fields.date.today(),
states={'done': [('readonly', True)]})
student = self.env['student.student'].search([('id','=',student_id)])
date_of_birth = student.date_of_birth
# date_of_birth = date.today()
# %Y-%m-%d %H:%M:%S
strp_date = datetime.strptime(str(date_of_birth),"%d %B, %Y")
# dob_result = datetime.strptime(date_of_birth, DEFAULT_SERVER_DATETIME_FORMAT).date()
# str_dob_result = str(date_of_birth)
strp_dob_result = num2words(strp_date)
strp_dob_result = strp_dob_result.upper()
return [{
'dob_in_words': strp_dob_result}]

You don't need strptime at all, you may use strftime. You still have to test if date is present. And i would make it as computed field as well.
_{name|inherit} = 'student.student'
#date_of_birth = fields.Date(...
date_of_birth_words = fields.Char(compute='_compute_dob_in_words', store=True)
#api.depends('date_of_birth')
def _compute_dob_in_words(self):
for student in self:
if student.date_of_birth:
date_of_birth = student.date_of_birth
month = date_of_birth.strftime('%B') #date_of_birth.month
day = num2words.num2words(date_of_birth.day, to='ordinal')
year = num2words.num2words(date_of_birth.year)
student.date_of_birth_words = "{} {} in year {}".format(day, month, year).upper()

Related

How to replace the day in a date with another date?

I'm trying to replace the day in my if statement for my date but I keep getting this output for my year.
05/15/5 besides 05/15/2020 . Code is below:
today_date = datetime.datetime.now()
date = today_date.date()
formatted_date = datetime.date.strftime(date, "%m/%d/%Y")
mmonth = date.month
myear = date.year
mdate = date.day
if mdate < 7:
m0weekend = formatted_date.replace(str(myear),str(mmonth),1)
else:
m0weekend = formatted_date.replace(str(myear),str(mmonth),15)
it's easier to replace the day before converting to a string:
date = date.replace(day=1)
or, in your case:
if mdate < 7:
m0weekend = date.replace(day=1)
else:
m0weekend = date.replace(day=15)
formatted_date is actually a string.
You are using the str.replace() method not the datetime.date.replace() method.
import datetime
today_date = datetime.datetime.now()
pre_formatted_date = today_date.date()
mmonth = pre_formatted_date.month
myear = pre_formatted_date.year
mdate = pre_formatted_date.day
if mdate < 7:
pre_formatted_date = pre_formatted_date.replace(day=1)
else:
pre_formatted_date = pre_formatted_date.replace(day=15)
print(pre_formatted_date)
formatted_date = pre_formatted_date.strftime("%m/%d/%Y")
print(formatted_date)
Which has the following output:
2020-05-15
05/15/2020
You might get today datetime.date directly from datetime rather than creating datetime.datetime and converting to date. After you have today you might create needed datetime.date and turn it into str, i.e.:
import datetime
today = datetime.date.today()
date = datetime.date(today.year, today.month, 1 if today.day < 7 else 15)
formatted_date = datetime.date.strftime(date, "%m/%d/%Y")
print(formatted_date) # 05/15/2020

Create objects based on date and time

I have an Event model, and each event will have different shows.
class Event(models.Model):
title = models.CharField(max_length=200)
class Show(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE)
date_time = models.DateTimeField(unique=True)
I have another Ticket model. Each ticket should be unique. Meaning each ticket will be unique and relate to a Show and a Seat.
class Ticket(models.Model):
show = models.ForeignKey(Show)
seat = models.ForeignKey(Seat)
class Meta:
unique_together = ('show', 'seat')
I need to create shows based on the start date and end date provide by the user. Suppose this is a JSON post:
{
"event_id": 1,
"start_date": "2018-02-16",
"end_date": "2018-02-20",
"time_list": ["11:00 AM", "8:00 PM"]
}
From the above JSON example, I need to create Show starting like this:
# Start with the start_date as the date, and for each time from the time_list
Show.objects.create(
event = 1,
date_time = datetime.strptime('2018-02-16 11:00 AM', "%Y-%m-%d %I:%M %p")
)
Show.objects.create(
event = 1,
date_time = datetime.strptime('2018-02-16 8:00 PM', "%Y-%m-%d %I:%M %p")
)
# Next date after the start_date, i.e., 16+1 = 17
Show.objects.create(
event = 1,
date_time = datetime.strptime('2018-02-17 8:00 PM', "%Y-%m-%d %I:%M %p")
)
.
.
.
# Create Show objects till the end_date and for each time from the time_list
Show.objects.create(
event = 1,
date_time = datetime.strptime('2018-02-20 8:00 PM', "%Y-%m-%d %I:%M %p")
)
Right now this is how I am creating Show objects:
def create_show_by_datetime(self, request):
event_id = request.data['event_id']
try:
event = Event.objects.get(id=event_id)
except Event.DoesNotExist:
return Response(
{'error': 'event with id: %s does not exist.' % event_id},
status=status.HTTP_400_BAD_REQUEST
)
start_date = request.data['start_date']
end_date = request.data['end_date']
time_list = request.data['time_list']
date_format = '%Y-%m-%d'
time_format = "%I:%M %p"
try:
datetime.strptime(start_date, date_format)
datetime.strptime(end_date, date_format)
for i in range(len(time_list)):
time = datetime.strptime(time_list[i], time_format)
except ValueError as e:
return Response(
{'error': 'Time was not in a supported format. %s' % e},
status=status.HTTP_400_BAD_REQUEST
)
delta_days = datetime.strptime(end_date, date_format).date() - datetime.strptime(start_date, date_format).date()
delta_days = delta_days.days + 1
dt = None
try:
with transaction.atomic():
for i in range(delta_days):
day = datetime.strptime(start_date, date_format) + timedelta(days=i)
for i in range(len(time_list)):
hrs = datetime.strptime(time_list[i], time_format).hour
mins = datetime.strptime(time_list[i], time_format).minute
dt = day + timedelta(hours=hrs, minutes=mins)
show = Show.objects.create(
event=event,
date_time=dt
)
return Response({"data": 'Post succesfull'}, status=status.HTTP_201_CREATED)
except IntegrityError as e:
return Response(
{
'error': "event with date and time already exsits. %s-%s-%s at %s:%s" % (
dt.day, dt.month, dt.year, dt.hour, dt.minute),
'detail': str(e)
}, status=status.HTTP_400_BAD_REQUEST
But I am hoping there's much more elegant way than how I am doing. I am using python 3, django 2 and django rest frameowork. How can I create Shows with the event, and date_time based on the event_id, start_date, end_date and the time_list?
My approach is a little bit different. You said in the question tag that you are using django-rest-framework.. So where are the serializers? :)
Lets create two serializers, one for user data validation (Because we don't trust the USER!) and one for multi data insert.
I haven't checked the code! But you can use it was an example...
class ShowEventSerializer(serializers.Serializer):
event_id = serializers.IntegerField()
start_date = serializers.DateField(required=True)
end_date = serializers.DateField(required=True)
time_list = serializers.ListField(
child=serializers.TimeField()
)
class Meta:
fields = ('event_id', 'start_date', 'end_date', 'time_list')
class ShowSerializer(serializers.Serializer):
date_time = serializers.DateTimeField()
class Meta:
model = Show
fields = ('event', 'date_time')
Now, with the serializers, we are going to validate the user data and then to create a json data object:
def create_show_by_datetime(self, request):
show_event_serializer = ShowEventSerializer(data=request.data)
if not show_event_serializer.is_valid():
return Response({'error': show_event_serializer.errors},status=status.HTTP_400_BAD_REQUEST)
event_id = show_event_serializer.data['event_id']
try:
event = Event.objects.get(id=event_id)
except Event.DoesNotExist:
return Response({'error': 'event with id: %s does not exist.' % event_id},status=status.HTTP_400_BAD_REQUEST)
start_date = show_event_serializer.data['start_date']
end_date = show_event_serializer.data['end_date']
time_list = show_event_serializer.data['time_list']
date_format = '%Y-%m-%d'
time_format = "%I:%M %p"
try:
datetime.strptime(start_date, date_format)
datetime.strptime(end_date, date_format)
for i in range(len(time_list)):
time = datetime.strptime(time_list[i], time_format)
except ValueError as e:
return Response(
{'error': 'Time was not in a supported format. %s' % e},
status=status.HTTP_400_BAD_REQUEST
)
delta_days = datetime.strptime(end_date, date_format).date() - datetime.strptime(start_date, date_format).date()
delta_days = delta_days.days + 1
dt = None
show_data = []
for i in range(delta_days):
day = datetime.strptime(start_date, date_format) + timedelta(days=i)
for i in range(len(time_list)):
hrs = datetime.strptime(time_list[i], time_format).hour
mins = datetime.strptime(time_list[i], time_format).minute
dt = day + timedelta(hours=hrs, minutes=mins)
show_data.append({
"event": event,
"date_time": dt
})
try:
with transaction.atomic():
show_serializer = ShowSerializer(data=show_data, many=True)
if show_serializer.is_valid():
show_serializer.save()
return Response({"data": 'Post succesfull'}, status=status.HTTP_201_CREATED)
except IntegrityError as e:
return Response(
{
'error': "event with date and time already exsits. %s-%s-%s at %s:%s" % (
dt.day, dt.month, dt.year, dt.hour, dt.minute),
'detail': str(e)
}, status=status.HTTP_400_BAD_REQUEST
So this code is basically the same as yours, with the difference of the way the objects are saved using the DRF. Look the show_data variable.
This solution is just a different way of looking at the question.
GOOD LUCK!
http://www.django-rest-framework.org/api-guide/serializers/
http://www.django-rest-framework.org/api-guide/fields/
Then your Show model should look like
from django.contrib.postgres.fields import ArrayField
class Show(models.Model):
event = models.ForeignKey(Event, on_delete=models.CASCADE)
start_date = models.DateField(blank=True, null=True)
end_date = models.DateField(blank=True, null=True)
board = ArrayField(
models.TimeField(blank=True, null=True),
size=10, # specify max array size
)
so you'll have model Show with specified DateFields and array of TimeFields.
django docs: Array Field, Time Field, Date Field
There are some tools in the datetime library that can give you a more streamlined approach to generating your times. You can use toordinal to turn a date into an integer and fromordinal to turn an integer back into a date; this makes a nice way to create a range of dates. And you can use combine to merge a date object and a time object into a datetime. I'd create the following function:
from datetime import datetime, date
def get_showtimes(post):
start = datetime.strptime(post['start_date'], '%Y-%m-%d')
end = datetime.strptime(post['end_date'], '%Y-%m-%d')
times = [datetime.strptime(t, '%I:%M %p').time() for t in post['time_list']]
for ordinal in range(start.toordinal(), end.toordinal() + 1):
date = date.fromordinal(date)
for time in times:
yield datetime.combine(date, time)
then, in your code, replace the second try: except: block and what follows it with:
try:
showtimes = list(get_showtimes(post))
except ValueError as e:
return Response(
{'error': 'Time was not in a supported format. %s' % e},
status=status.HTTP_400_BAD_REQUEST
)
try:
with transaction.atomic():
for showtime in showtimes:
show = Show.objects.create(event=event, date_time=showtime)
except IntegrityError as e:
# etc.
I am leaving the validation part and only focusing on generating Show objects from the given data:
data = request.data
date_format = '%Y-%m-%d'
time_format = "%I:%M %p"
show_time_format = f"{date_format} {time_format}"
# get the total number of days by parsing start and end dates
start_date = datetime.strptime(data['start_date'], date_format)
end_date = datetime.strptime(data['end_date'], date_format)
total_days = (end_date - start_date).days + 1
# Get the timings for the first day.
# We will use this to generate the timings for the rest of the days.
first_day_timings = [
datetime.strptime(f"{data['start_date']} {show_time}", show_time_format)
for show_time in data['time_list']
]
# generate all show objects using list comprehension and bulk create later
show_objects = [
Show(event=event, date_time=first_day_timing + timedelta(days=day_cnt))
for day_cnt in range(total_days)
for first_day_timing in first_day_timings
]
Show.objects.bulk_create(show_objects)
Enhancements made on the existing code:
Reduced the number of instances date/time is getting parsed and hours/minutes are getting computed.
Use list comprehension to generate show objects and bulk create instead of creating one object at a time in a transaction.

Slots Creation based on date and time(float) field

I have two date field.
from_date and
to_date
In One2many line item, there is three float fields
from_time ,to_time and interval
Slot have to be created based on the above parameters.
Example:
from_date = '2017-07-21'
to_date = '2017-07-21'
the duration is one day.
The One2many line items have the values
from_time = 9.0
to_time = 10.0
interval = 30(in minutes)
The output should generate two slots
1. '2017-07-21 09:00:00' '2017-07-21 09:30:00'
2. '2017-07-21 09:30:00' '2017-07-21 10:00:00'
It should generate two line items.
If the duration is for week.
it should generate 2 * 7 = 14 slots.
I have used the code which generates for one day.
#api.one
def generate(self):
cr = self.env.cr
uid = self.env.uid
context = self.env.context
event = self.pool.get('calendar.event')
slot = self.pool.get('slot.booking')
old_data_id = slot.search(cr, uid, [('slot_id', '=',self.id)], context=context)
slot.unlink(cr, uid ,old_data_id)
for each in self.shift_line:
if each.interval > 60 or each.interval == 0:
raise osv.except_osv(_('Attention!'), _('Please enter interval timings in minutes range like (10-60) '))
interval = each.interval
fmt = "%Y-%m-%d"
start_date = datetime.strptime(self.from_date, fmt)
end_date = datetime.strptime(self.to_date, fmt)
days = []
date = start_date
pdb.set_trace()
str_start_time = '%s %s' % (self.from_date,'{0:02.0f}:{1:02.0f}'.format(*divmod(each.from_time * 60, 60)))+':00'
str_end_time = '%s %s' % (self.from_date,'{0:02.0f}:{1:02.0f}'.format(*divmod(each.to_time * 60, 60)))+':00'
time = datetime.strptime(str_start_time, '%Y-%m-%d %H:%M:%S')
end = datetime.strptime(str_end_time, '%Y-%m-%d %H:%M:%S')
while date <= end_date:
hours = []
while time <= end:
hours.append(time.strftime("%Y-%m-%d %H:%M:%S"))
time += timedelta(minutes=interval)
date += timedelta(days=1)
time += timedelta(days=1)
end += timedelta(days=1)
days.append(hours)
print "\n\n\n\n\nn\+++++++++++++++++++++days",days
for hours in days[0][:-1]:
val = datetime.strptime(hours, '%Y-%m-%d %H:%M:%S')
val = val + timedelta(minutes=interval)
values = {
'name' : 'Slot for ' + self.employee_id.name,
'start_datetime' : hours,
'stop_datetime' : str(val),
'slot_id' : self.id,
'shift_lines_id' : each.id,
'partner_id': self.employee_id.id,
'duration' : each.interval,
}
print "\n\n\n\n\n\n\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++values",values
slot.create(cr, uid, values, context=context)
Any help for multiple days is appreciated.
ist_timedelta = timedelta(seconds=((time in seconds)-10800))
adding this will give the exact answer, here 10800 is because of 3 hours difference of UTC to KSA.

How to get only date from "Date" field in python

def generate_leave(self, cr, uid,ids, fields, context=None):
if context is None:
context = {}
month_split = self.browse( cr, uid,ids)
print "\n\n\n\n\n\n DATEE",month_split.name
dt = datetime.strptime(month_split.name, "%Y-%m-%d")
# date= dt.strftime(month_split.name[],'%Y-%m-%d')
# print "\n\n\n\n\n DAT",date
year = dt.year
print "\n\n\n\n YER",year
month = dt.month
print "\n\n\n MNTH",month
currentMonth = datetime.now().month
print "\n\n\n\n\n CURR MNTH",currentMonth
date = dt.date
print "\n\n\n\n\n\n DATTE",date
date = datetime.now().day
print "\n\n\n\n\n\n DATEE",date
This is my code. I am able to get current date separately. But in my scenario user will input a date and I want to take only the "Date" from that input, I don't want month and year.

Finding out if its a leap year and setting accordingly

I have a form that has an initial end_date. I am having a Value error because this year is a leap year and we are currently in February.
My code has a end day of 30 but I am having trouble figuring out how to write the code that will discover if its a leap year and set the initial end_date to the correct last day of february.
Here is my forms.py that controls the end_date initial value
class MaturityLetterSetupForm(forms.Form):
def __init__(self, *args, **kwargs):
from datetime import datetime
today = datetime.today()
start_year = today.year
start_month = today.month
start_date = datetime(start_year, start_month, 1)
try:
end_date = datetime(start_year, start_month, 30)
except ValueError:
end_date = datetime(start_year, start_month, ?)
super(MaturityLetterSetupForm, self).__init__(*args, **kwargs)
self.fields['start_date'] = forms.DateField(initial=start_date.strftime("%B %d, %Y"),
widget=forms.TextInput(attrs={'class':'datepicker', 'value': today }))
self.fields['end_date'] = forms.DateField(initial=end_date.strftime("%B %d, %Y"),
widget=forms.TextInput(attrs={'class':'datepicker', 'value': today }))
EDIT
After speaking to #Paul
my init became:
def __init__(self, *args, **kwargs):
from datetime import datetime
import calendar
today = datetime.today()
start_year = today.year
start_month = today.month
start_date = datetime(start_year, start_month, 1)
if calendar.isleap(start_year) and today.month == 2:
end_date = datetime(start_year, start_month, calendar.mdays[today.month]+1)
else:
end_date = datetime(start_year, start_month, calendar.mdays[today.month])
super(MaturityLetterSetupForm, self).__init__(*args, **kwargs)
self.fields['start_date'] = forms.DateField(initial=start_date.strftime("%B %d, %Y"),
widget=forms.TextInput(attrs={'class':'datepicker', 'value': today }))
self.fields['end_date'] = forms.DateField(initial=end_date.strftime("%B %d, %Y"),
widget=forms.TextInput(attrs={'class':'datepicker', 'value': today }))
Which finds the last day of the current month.
How about calendar.isleap(year) ?
Also, don't use try/except to handle this but an if conditional. Something like:
if calendar.isleap(year):
do_stuff
else:
do_other_stuff

Categories