Skip to content

Commit aaba863

Browse files
committed
updates
1 parent 7b43f35 commit aaba863

6 files changed

Lines changed: 239 additions & 38 deletions

File tree

core/api/bookings/events/artisan.py

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,18 @@ def cancel_offer_artisan(uid, data):
411411
def handle_location_arrival(uid, data):
412412
""" triggered when artisan arrives at location """
413413
room = data['booking_id']
414+
bk = Booking.query.get(data['booking_id'])
415+
416+
if bk.status != BookingStatusEnum.PENDING:
417+
emit(
418+
'error',
419+
error_response(
420+
"Invalid action: Cannot carry out",
421+
" action on booking at this stage",
422+
uid
423+
)
424+
)
425+
return
414426

415427
matched_artisan = redis_4.hget('booking_id_to_artisan', room)
416428
current_artisan = Artisan.get_by_user_id(uid)
@@ -458,6 +470,16 @@ def handle_job_begin(uid, data):
458470
with db.session() as sess:
459471
artisan = Artisan.get_by_user_id(uid)
460472
bk = Booking.query.get(data['booking_id'])
473+
if bk.status != BookingStatusEnum.ARTISAN_ARRIVED:
474+
emit(
475+
'error',
476+
error_response(
477+
"Invalid action: Cannot carry out",
478+
" action on booking at this stage",
479+
uid
480+
)
481+
)
482+
return
461483

462484
room = data['booking_id']
463485

@@ -585,6 +607,16 @@ def customer_approval(uid, data):
585607
)
586608
return
587609

610+
room = data['booking_id']
611+
matched_artisan = redis_4.hget('booking_id_to_artisan', room)
612+
current_artisan = Artisan.get_by_user_id(uid)
613+
if matched_artisan != current_artisan.user_id:
614+
emit(
615+
'error',
616+
error_response(messages.ARTISAN_NOT_MATCHED_TO_BOOKING, uid)
617+
)
618+
return
619+
588620
# inform customer
589621
payload = {
590622
'payload': data,
@@ -618,7 +650,28 @@ def clock_in(uid, data):
618650
error_response(messages.INVALID_CLOCK_IN_ATTEMPT, uid)
619651
)
620652
return
653+
room = data['booking_id']
654+
matched_artisan = redis_4.hget('booking_id_to_artisan', room)
655+
current_artisan = Artisan.get_by_user_id(uid)
656+
if matched_artisan != current_artisan.user_id:
657+
emit(
658+
'error',
659+
error_response(messages.ARTISAN_NOT_MATCHED_TO_BOOKING, uid)
660+
)
661+
return
662+
if bk.clock_in_flag:
663+
emit(
664+
'error',
665+
error_response(
666+
"Invalid action: Already clocked! "
667+
"Clock-out first",
668+
uid
669+
)
670+
)
671+
return
621672
bk.add_clock_event(sess)
673+
bk.clock_in_flag = True
674+
sess.commit()
622675

623676
# signal customer
624677
payload = {
@@ -647,8 +700,28 @@ def clock_out(uid, data):
647700
error_response(messages.INVALID_CLOCK_OUT_ATTEMPT, uid)
648701
)
649702
return
703+
room = data['booking_id']
704+
matched_artisan = redis_4.hget('booking_id_to_artisan', room)
705+
current_artisan = Artisan.get_by_user_id(uid)
706+
if matched_artisan != current_artisan.user_id:
707+
emit(
708+
'error',
709+
error_response(messages.ARTISAN_NOT_MATCHED_TO_BOOKING, uid)
710+
)
711+
return
712+
if not bk.clock_in_flag:
713+
emit(
714+
'error',
715+
error_response(
716+
"Invalid action: Can't clock out without "
717+
"first clocking in",
718+
uid
719+
)
720+
)
721+
return
650722
bk.add_clock_event(sess, clock_in=False)
651-
723+
bk.clock_in_flag = False
724+
sess.commit()
652725
# signal customer
653726
payload = {
654727
'payload': messages.ARTISAN_CLOCKED_OUT,

core/api/bookings/views.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import uuid
22

3+
from sqlalchemy import select, and_
34
from flask import request, render_template
45
from loguru import logger
56

@@ -9,7 +10,8 @@
910
from schemas import (
1011
BookingSchema,
1112
UserSchema,
12-
BlobSchema
13+
BlobSchema,
14+
BookingWorkDaySchema
1315
)
1416
from models.user_models import Permission
1517
from uuid import uuid4
@@ -156,6 +158,38 @@ def delete_booking(current_user, booking_id):
156158
return gen_response(200, message=msg)
157159

158160

161+
@bookings.get('/<booking_id>/workingdays')
162+
@login_required
163+
@permission_required(Permission.service_request)
164+
def list_clocks(current_user, booking_id):
165+
with db.session() as sess:
166+
stmt = select(Booking).where(
167+
and_(
168+
Booking.customer_id == current_user.user_id,
169+
Booking.booking_id == booking_id
170+
)
171+
)
172+
bk = sess.scalar(stmt)
173+
if not bk:
174+
return error_response(
175+
404,
176+
"Booking not found, or you didn't request this originally"
177+
)
178+
179+
schema = BookingWorkDaySchema(
180+
many=True,
181+
only=(
182+
'booking_id', 'work_sessions', 'id',
183+
'name', 'date',
184+
)
185+
)
186+
working_days = bk.working_days
187+
return gen_response(
188+
200,
189+
data=schema.dump(working_days)
190+
)
191+
192+
159193
@bookings.route('/see')
160194
def see():
161195
return render_template('bookings/index.html')

migrations/versions/2025-10-13__b8ec34f70d9c.py

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -51,25 +51,29 @@ def upgrade():
5151
"""))
5252

5353
op.create_table('booking_workday',
54-
sa.Column('contract_id', sa.Integer(), nullable=True),
55-
sa.Column('booking_id', sa.String(), nullable=True),
56-
sa.Column('name', sa.Enum('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY', name='bookingworkdayenum'), nullable=False),
57-
sa.Column('date', sa.Date(), nullable=True),
58-
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
59-
sa.Column('created_at', sa.DateTime(), nullable=False),
60-
sa.Column('updated_at', sa.DateTime(), nullable=True),
61-
sa.ForeignKeyConstraint(['booking_id'], ['booking.booking_id'], ),
62-
sa.ForeignKeyConstraint(['contract_id'], ['booking_contract.id'], ),
63-
sa.PrimaryKeyConstraint('id')
54+
sa.Column('contract_id', sa.Integer(), nullable=True),
55+
sa.Column('booking_id', sa.String(), nullable=True),
56+
sa.Column('name', sa.Enum('MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY', name='bookingworkdayenum'), nullable=False),
57+
sa.Column('date', sa.Date(), nullable=True),
58+
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
59+
sa.Column('created_at', sa.DateTime(), nullable=False),
60+
sa.Column('updated_at', sa.DateTime(), nullable=True),
61+
sa.ForeignKeyConstraint(['booking_id'], ['booking.booking_id'], ),
62+
sa.ForeignKeyConstraint(['contract_id'], ['booking_contract.id'], ),
63+
sa.PrimaryKeyConstraint('id')
6464
)
65-
op.create_table('booking_clock_event',
66-
sa.Column('working_day_id', sa.Integer(), nullable=False),
67-
sa.Column('event_type', sa.Enum('CLOCK_IN', 'CLOCK_OUT', name='bookingclockeventtypeenum'), nullable=False),
68-
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
69-
sa.Column('created_at', sa.DateTime(), nullable=False),
70-
sa.Column('updated_at', sa.DateTime(), nullable=True),
71-
sa.ForeignKeyConstraint(['working_day_id'], ['booking_workday.id'], ),
72-
sa.PrimaryKeyConstraint('id')
65+
op.create_table('booking_work_session',
66+
sa.Column('working_day_id', sa.Integer(), nullable=False),
67+
sa.Column('clock_in', sa.DateTime(), nullable=True),
68+
sa.Column('clock_out', sa.DateTime(), nullable=True),
69+
sa.Column('booking_id', sa.String(), nullable=False),
70+
# sa.Column('event_type', sa.Enum('CLOCK_IN', 'CLOCK_OUT', name='bookingclockeventtypeenum'), nullable=False),
71+
sa.Column('id', sa.Integer(), autoincrement=True, nullable=False),
72+
sa.Column('created_at', sa.DateTime(), nullable=False),
73+
sa.Column('updated_at', sa.DateTime(), nullable=True),
74+
sa.ForeignKeyConstraint(['working_day_id'], ['booking_workday.id'], ),
75+
sa.ForeignKeyConstraint(['booking_id'], ['booking.booking_id'], ),
76+
sa.PrimaryKeyConstraint('id')
7377
)
7478

7579
with op.batch_alter_table('wallet', schema=None) as batch_op:
@@ -80,6 +84,28 @@ def upgrade():
8084
)
8185
)
8286

87+
with op.batch_alter_table('booking', schema=None) as batch_op:
88+
batch_op.add_column(
89+
sa.Column(
90+
'clock_in_flag', sa.Boolean(),
91+
nullable=True, server_default='false'
92+
)
93+
)
94+
batch_op.add_column(
95+
sa.Column(
96+
'current_work_session_id',
97+
sa.Integer(),
98+
nullable=True
99+
)
100+
)
101+
op.execute(
102+
"""
103+
ALTER TABLE booking
104+
ADD CONSTRAINT fk_current_work_session_id
105+
FOREIGN KEY (current_work_session_id)
106+
REFERENCES booking_work_session (id);
107+
"""
108+
)
83109
# ### end Alembic commands ###
84110

85111

@@ -99,14 +125,20 @@ def downgrade():
99125
SET status = CASE
100126
WHEN status::text = 'IN_PROGRESS' THEN '{old_enum_values[0]}'::{old_enum_name}
101127
WHEN status::text = 'COMPLETED' THEN '{old_enum_values[1]}'::{old_enum_name}
128+
WHEN status::text = 'PENDING' THEN NULL
102129
ELSE status
103130
END
104131
"""))
105132

106133
with op.batch_alter_table('wallet', schema=None) as batch_op:
107134
batch_op.drop_column('is_activated')
108-
op.drop_table('booking_clock_event')
135+
136+
with op.batch_alter_table('booking', schema=None) as batch_op:
137+
batch_op.drop_column('clock_in_flag')
138+
batch_op.drop_constraint('fk_current_work_session_id')
139+
batch_op.drop_column('current_work_session_id')
140+
141+
op.drop_table('booking_work_session')
109142
op.drop_table('booking_workday')
110143
op.execute("DROP TYPE bookingworkdayenum")
111-
op.execute("DROP TYPE bookingclockeventtypeenum")
112144
# ### end Alembic commands ###

models/bookings.py

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,18 +78,32 @@ class BookingWorkDay(BaseModelPR, TimestampMixin, db.Model):
7878
db.ForeignKey('booking_contract.id'),
7979
nullable=True
8080
)
81-
booking_id = db.Column(db.String, db.ForeignKey('booking.booking_id'))
81+
booking_id = db.Column(
82+
db.String,
83+
db.ForeignKey('booking.booking_id'),
84+
nullable=False
85+
)
8286
name = db.Column(db.Enum(BookingWorkDayEnum), nullable=False)
8387
date = db.Column(db.Date)
88+
work_sessions = db.relationship(
89+
'BookingWorkSession',
90+
backref='booking_work_day'
91+
)
8492

8593

86-
class BookingClockEvent(BaseModelPR, TimestampMixin, db.Model):
94+
class BookingWorkSession(BaseModelPR, TimestampMixin, db.Model):
8795
working_day_id = db.Column(
8896
db.Integer,
8997
db.ForeignKey('booking_workday.id'),
9098
nullable=False
9199
)
92-
event_type = db.Column(db.Enum(BookingClockEventTypeEnum), nullable=False)
100+
booking_id = db.Column(
101+
db.String,
102+
db.ForeignKey('booking.booking_id'),
103+
nullable=False
104+
)
105+
clock_in = db.Column(db.DateTime)
106+
clock_out = db.Column(db.DateTime)
93107

94108

95109
class BookingContract(TimestampMixin, BaseModelPR, db.Model):
@@ -143,7 +157,6 @@ def get_by_name(cls, val):
143157

144158
class Booking(TimestampMixin, db.Model):
145159
# TODO: Implement activity track/logs
146-
147160
# Table Columns
148161
booking_id = db.Column(db.String, primary_key=True, unique=True)
149162
customer_id = db.Column(
@@ -183,12 +196,21 @@ class Booking(TimestampMixin, db.Model):
183196
db.Enum(BookingPaymentMethod),
184197
index=True
185198
)
199+
clock_in_flag = db.Column(
200+
db.Boolean, server_default='false',
201+
default=False
202+
)
186203
booking_contract = db.relationship(
187204
'BookingContract',
188205
backref='booking',
189206
uselist=False
190207
)
208+
current_work_session_id = db.Column(
209+
db.Integer,
210+
db.ForeignKey('booking_work_session.id')
211+
)
191212
images = db.relationship('Blob', backref='booking')
213+
working_days = db.relationship('BookingWorkDay', backref='booking')
192214

193215
def update_start_time(self):
194216
self.start_time = dt.utcnow()
@@ -228,12 +250,14 @@ def start_booking(self, sess):
228250

229251
sess.add(new_work_day)
230252
sess.flush()
231-
clock_in = BookingClockEvent(
253+
clock = BookingWorkSession(
232254
working_day_id=new_work_day.id,
233-
event_type=BookingClockEventTypeEnum.CLOCK_IN
255+
clock_in=current_day,
256+
booking_id=self.booking_id
234257
)
235-
sess.add(clock_in)
258+
sess.add(clock)
236259
sess.flush()
260+
self.current_work_session_id = clock.id
237261

238262
def add_clock_event(self, sess, clock_in=True):
239263
current_day = dt.now(datetime.timezone.utc)
@@ -249,19 +273,32 @@ def add_clock_event(self, sess, clock_in=True):
249273
if not working_day:
250274
working_day = BookingWorkDay(
251275
name=BookingWorkDayEnum[dow.upper()],
252-
date=current_day.date()
276+
date=current_day.date(),
277+
booking_id=self.booking_id
253278
)
254279
if self.contract_type:
255280
working_day.contract_id = self.booking_contract.id
281+
sess.add(working_day)
256282
sess.flush()
283+
257284
# add clock-in
258-
clock_in = BookingClockEvent(
259-
working_day_id=working_day.id
260-
)
261285
if clock_in:
262-
clock_in.event_type = BookingClockEventTypeEnum.CLOCK_IN
286+
clock = BookingWorkSession(
287+
working_day_id=working_day.id,
288+
booking_id=self.booking_id,
289+
clock_in=current_day
290+
)
291+
sess.add(clock)
292+
sess.flush()
293+
self.current_work_session_id = clock.id
263294
else:
264-
clock_in.event_type = BookingClockEventTypeEnum.CLOCK_OUT
295+
self.current_work_session(sess).clock_out = current_day
265296

266-
sess.add(clock_in)
267297
sess.flush()
298+
299+
def current_work_session(self, sess):
300+
return sess.scalar(
301+
select(BookingWorkSession).where(
302+
BookingWorkSession.id == self.current_work_session_id
303+
)
304+
)

0 commit comments

Comments
 (0)