Skip to content

Commit cff0ccb

Browse files
committed
updates
1 parent f3f5f31 commit cff0ccb

10 files changed

Lines changed: 228 additions & 38 deletions

File tree

core/api/bookings/events/artisan.py

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def handle_updates(msg):
241241
@socketio.on('accept_offer', namespace='/artisan')
242242
@parse_event_data
243243
@valid_auth_required
244-
def get_updates(uid, data):
244+
def accept_offer(uid, data):
245245
""" triggered when artisan accepts offer """
246246
from tasks.booking_tasks import assign_artisan_to_booking
247247

@@ -276,7 +276,6 @@ def get_updates(uid, data):
276276
).dump(
277277
Artisan.get_by_user_id(uid)
278278
)
279-
print(artisan)
280279
lon, lat = redis_5.geopos(
281280
artisan['job_category'],
282281
uid
@@ -289,7 +288,6 @@ def get_updates(uid, data):
289288
route_dets = query.json()
290289
logger.error(route_dets)
291290
route_dets = route_dets['rows'][0]['elements'][0]
292-
print(artisan, "===afe===")
293291
data = BookingAcceptedSchema().load(
294292
{
295293
'booking_id': data['booking_id'],
@@ -344,12 +342,31 @@ def cancel_offer_artisan(uid, data):
344342
data = schema.load(data)
345343
except Exception as e:
346344
raise DataValidationError(messages.SCHEMA_ERROR, errors=e)
347-
348345
room = data['booking_id']
349346

347+
matched_artisan = redis_4.hget('booking_id_to_artisan', room)
348+
current_artisan = Artisan.get_by_user_id(uid)
349+
if not redis_.exists(room):
350+
emit(
351+
'error',
352+
error_response(messages.BOOKING_UNAVAILABLE, uid)
353+
)
354+
return
355+
if matched_artisan != current_artisan.user_id:
356+
emit(
357+
'error',
358+
error_response(messages.INVALID_A_CANCEL_OFFER, uid)
359+
)
360+
return
361+
350362
# update status of booking
351363
try:
352-
update_booking_status(data)
364+
update_booking_status(
365+
{
366+
'status': BookingStatusEnum.ARTISAN_CANCELLED,
367+
**data
368+
}
369+
)
353370
except Exception as e:
354371
logger.exception(e)
355372
send_event(
@@ -359,12 +376,21 @@ def cancel_offer_artisan(uid, data):
359376
)
360377

361378
# remove from queue once canceled
379+
# TODO: check which dbs are for what
362380
redis_2.delete(room)
381+
redis_.delete(room)
363382

364-
socketio.emit(
383+
payload = {
384+
'payload': messages.dynamic_msg(messages.BOOKING_CANCELLED, "artisan"),
385+
'recipient': redis_4.hget(
386+
'booking_id_to_uid',
387+
room
388+
)
389+
}
390+
send_event(
365391
'offer_cancelled',
366-
messages.dynamic_msg(messages.BOOKING_CANCELLED, "artisan"),
367-
to=room
392+
payload,
393+
'/customer'
368394
)
369395

370396

core/api/bookings/events/customer.py

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,20 @@
44
redis_2,
55
redis_4
66
)
7+
from models.bookings import BookingStatusEnum
78
from core.api.auth.auth_helper import (
89
auth_param_required,
910
valid_auth_required
1011
)
1112
from tasks.events import send_event
13+
from tasks.booking_tasks import update_booking_status
1214
from core.exc import DataValidationError
1315
from core.api.bookings.events.utils import parse_event_data
1416
from schemas.bookings_schema import BookingStartSchema
1517
from core.api.auth.auth_helper import verify_token
1618
from tasks.booking_tasks import confirm_job_details
1719
from .. import messages
20+
from .utils import error_response
1821

1922
from loguru import logger
2023
from flask_socketio import emit, join_room
@@ -88,14 +91,16 @@ def booking_upate(data):
8891

8992
@socketio.on('join_chat', namespace='/chat')
9093
@parse_event_data
91-
def enter_customer_artisan_chat(data):
94+
@valid_auth_required
95+
def enter_customer_artisan_chat(uid, data):
9296
room = data['booking_id']
9397
join_room(room, namespace='/chat')
9498

9599

96100
@socketio.on('cancel_offer', namespace='/customer')
97101
@parse_event_data
98-
def cancel_offer(data):
102+
@valid_auth_required
103+
def cancel_offer(uid, data):
99104
room = data['booking_id']
100105

101106
# update state of offer in cache
@@ -107,15 +112,39 @@ def cancel_offer(data):
107112
logger.info('Client canceled; removing booking with id: {} from cache'.format(
108113
data['booking_id']
109114
))
110-
socketio.emit(
111-
'offer_cancelled',
112-
"Client cancelled offer",
113-
namespace='/artisan',
114-
to=redis_4.hget(
115-
'booking_id_to_uid',
115+
customer_id = redis_4.hget('booking_id_to_uid', room)
116+
if not redis_.exists(room):
117+
emit(
118+
'error',
119+
error_response(messages.BOOKING_UNAVAILABLE, uid)
120+
)
121+
return
122+
if customer_id != uid:
123+
emit(
124+
'error',
125+
error_response(messages.INVALID_CANCEL_OFFER, uid)
126+
)
127+
return
128+
payload = {
129+
'payload': "Client cancelled offer",
130+
'recipient': redis_4.hget(
131+
'booking_id_to_artisan',
116132
room
117133
)
134+
}
135+
send_event(
136+
'offer_cancelled',
137+
payload,
138+
'/artisan'
139+
)
140+
# update status of booking
141+
update_booking_status(
142+
{
143+
'status': BookingStatusEnum.CUSTOMER_CANCELLED,
144+
**data
145+
}
118146
)
147+
redis_.delete(room)
119148

120149

121150
@socketio.on('msg', namespace='/chat')

core/api/bookings/messages.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
BOOKING_MADE = "booking request fulfilled"
44
NEW_BOOKING_MADE = "new booking made"
55
BOOKING_CANCELLED = "{} canceled booking - booking no longer available"
6+
BOOKING_UNAVAILABLE = "booking no longer available or not found"
67
ARTISAN_ARRIVES = "artisan has reached client location"
78
JOB_STARTED = "new job initiated successfully"
89
JOB_COMPLETED = "job completed"
@@ -16,6 +17,9 @@
1617
BOOKING_DETAILS_CONFIRMED = 'customer has confirmed and accepted the terms for this job'
1718
BOOKING_DETAILS_ALREADY_CONFIRMED = 'customer has already confirmed this booking nau'
1819

20+
INVALID_A_CANCEL_OFFER = "You can't cancel an offer that was never assigned to you - 🤡"
21+
INVALID_C_CANCEL_OFFER = "You can't cancel a booking that you didn't request - 🤡"
22+
1923

2024
def dynamic_msg(msg: str, val):
2125
return msg.format(val)

core/api/bookings/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def create_booking(current_user):
7676
'booking_id': new_order.booking_id
7777
}
7878
to_be_uploaded = [{**_base_img, **img} for img in images['files']]
79-
images_schema = BlobSchema(many=True)
79+
images_schema = BlobSchema(uid=current_user.id, many=True)
8080
images = images_schema.load(to_be_uploaded)
8181
for img in images:
8282
img.blob_id = uuid.uuid4().hex
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
"""empty message
2+
3+
Revision ID: 16f917e0f7c7
4+
Revises: 0b3e7aac77c7
5+
Create Date: 2025-09-01 10:24:21.024944
6+
7+
"""
8+
from alembic import op
9+
import sqlalchemy as sa
10+
from sqlalchemy.dialects import postgresql
11+
12+
# revision identifiers, used by Alembic.
13+
revision = '16f917e0f7c7'
14+
down_revision = '0b3e7aac77c7'
15+
branch_labels = None
16+
depends_on = None
17+
18+
# old_enum = postgresql.ENUM(
19+
# 'IN_PROGRESS', 'COMPLETED',
20+
# 'CANCELLED', 'ARTISAN_ARRIVED',
21+
# name='bookingstatusenum'
22+
# )
23+
# new_enum = postgresql.ENUM(
24+
# 'IN_PROGRESS', 'COMPLETED', 'ARTISAN_CANCELLED',
25+
# 'CUSTOMER_CANCELLED', 'ARTISAN_ARRIVED',
26+
# name='bookingstatusenum'
27+
# )
28+
old_enum_name = 'bookingstatusenum'
29+
new_enum_name = 'bookingstatusenum_new'
30+
old_enum_values = ('IN_PROGRESS', 'COMPLETED', 'CANCELLED', 'ARTISAN_ARRIVED')
31+
new_enum_values = ('IN_PROGRESS', 'COMPLETED', 'ARTISAN_CANCELLED', 'CUSTOMER_CANCELLED', 'ARTISAN_ARRIVED')
32+
33+
34+
def upgrade():
35+
op.execute(f"CREATE TYPE {new_enum_name} AS ENUM ({', '.join(f'\'{v}\'' for v in new_enum_values)})")
36+
op.alter_column(
37+
'booking', 'status',
38+
existing_type=postgresql.ENUM(*old_enum_values, name=old_enum_name),
39+
type_=postgresql.ENUM(*new_enum_values, name=new_enum_name),
40+
postgresql_using=f"status::text::{new_enum_name}"
41+
)
42+
op.execute(f"DROP TYPE {old_enum_name}")
43+
op.execute(f"ALTER TYPE {new_enum_name} RENAME TO {old_enum_name}")
44+
op.execute(sa.text(f"""
45+
UPDATE booking
46+
SET status = CASE
47+
WHEN status::text = 'IN_PROGRESS' THEN '{new_enum_values[0]}'::{old_enum_name}
48+
WHEN status::text = 'COMPLETED' THEN '{new_enum_values[1]}'::{old_enum_name}
49+
ELSE status
50+
END
51+
"""))
52+
# ### commands auto generated by Alembic - please adjust! ###
53+
with op.batch_alter_table('booking', schema=None) as batch_op:
54+
batch_op.create_index(batch_op.f('ix_booking_artisan_id'), ['artisan_id'], unique=False)
55+
batch_op.create_index(batch_op.f('ix_booking_category_id'), ['category_id'], unique=False)
56+
batch_op.create_index(batch_op.f('ix_booking_contract_type'), ['contract_type'], unique=False)
57+
batch_op.create_index(batch_op.f('ix_booking_customer_id'), ['customer_id'], unique=False)
58+
batch_op.create_index(batch_op.f('ix_booking_payment_method'), ['payment_method'], unique=False)
59+
batch_op.create_index(batch_op.f('ix_booking_settlement_type'), ['settlement_type'], unique=False)
60+
# ### end Alembic commands ###
61+
62+
63+
def downgrade():
64+
# ### commands auto generated by Alembic - please adjust! ###
65+
op.execute(f"CREATE TYPE {old_enum_name}_old AS ENUM ({', '.join(f'\'{v}\'' for v in old_enum_values)})")
66+
op.alter_column(
67+
'booking', 'status',
68+
existing_type=postgresql.ENUM(*new_enum_values, name=old_enum_name),
69+
type_=postgresql.ENUM(*old_enum_values, name=f'{old_enum_name}_old'),
70+
postgresql_using=f"status::text::{old_enum_name}_old"
71+
)
72+
op.execute(f"DROP TYPE {old_enum_name}")
73+
op.execute(f"ALTER TYPE {old_enum_name}_old RENAME TO {old_enum_name}")
74+
op.execute(sa.text(f"""
75+
UPDATE booking
76+
SET status = CASE
77+
WHEN status::text = 'IN_PROGRESS' THEN '{old_enum_values[0]}'::{old_enum_name}
78+
WHEN status::text = 'COMPLETED' THEN '{old_enum_values[1]}'::{old_enum_name}
79+
ELSE status
80+
END
81+
"""))
82+
with op.batch_alter_table('booking', schema=None) as batch_op:
83+
batch_op.drop_index(batch_op.f('ix_booking_settlement_type'))
84+
batch_op.drop_index(batch_op.f('ix_booking_payment_method'))
85+
batch_op.drop_index(batch_op.f('ix_booking_customer_id'))
86+
batch_op.drop_index(batch_op.f('ix_booking_contract_type'))
87+
batch_op.drop_index(batch_op.f('ix_booking_category_id'))
88+
batch_op.drop_index(batch_op.f('ix_booking_artisan_id'))
89+
# ### end Alembic commands ###

models/bookings.py

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@
3030

3131

3232
class BookingStatusEnum(SerializableEnum):
33-
IN_PROGRESS = 8
34-
COMPLETED = 4
35-
CANCELLED = 2
33+
IN_PROGRESS = 16
34+
COMPLETED = 8
35+
ARTISAN_CANCELLED = 4
36+
CUSTOMER_CANCELLED = 2
3637
ARTISAN_ARRIVED = 1
3738

3839

@@ -101,25 +102,43 @@ class Booking(TimestampMixin, db.Model):
101102

102103
# Table Columns
103104
booking_id = db.Column(db.String, primary_key=True, unique=True)
104-
customer_id = db.Column(db.String, db.ForeignKey('user.user_id'))
105-
category_id = db.Column(db.Integer, db.ForeignKey('bookingcategory.id'))
106-
artisan_id = db.Column(db.String, db.ForeignKey('artisan.artisan_id'))
105+
customer_id = db.Column(
106+
db.String, db.ForeignKey('user.user_id'),
107+
index=True
108+
)
109+
category_id = db.Column(
110+
db.Integer, db.ForeignKey('bookingcategory.id'),
111+
index=True
112+
)
113+
artisan_id = db.Column(
114+
db.String, db.ForeignKey('artisan.artisan_id'),
115+
index=True
116+
)
107117
start_time = db.Column(db.Date)
108118
end_time = db.Column(db.Date)
109119
location = db.Column(Geometry(geometry_type='POINT', srid='4326'))
110120
description = db.Column(db.Text())
111121
status = db.Column(db.Enum(BookingStatusEnum))
112122
payment_id = db.Column(db.String, db.ForeignKey('payment.payment_id'))
113-
contract_type = db.Column("contract_type", db.Boolean, default=False)
123+
contract_type = db.Column(
124+
"contract_type",
125+
db.Boolean,
126+
default=False,
127+
index=True
128+
)
114129
artisan_rating = db.Column(db.Integer)
115130
customer_rating = db.Column(db.Integer)
116131
settlement_type = db.Column(
117132
db.Enum(
118133
SettlementEnum
119-
), nullable=True
134+
), nullable=True,
135+
index=True
120136
)
121137
details_confirmed = db.Column(db.Boolean, default=False)
122-
payment_method = db.Column(db.Enum(BookingPaymentMethod))
138+
payment_method = db.Column(
139+
db.Enum(BookingPaymentMethod),
140+
index=True
141+
)
123142
booking_contract = db.relationship(
124143
'BookingContract',
125144
backref='booking',

schemas/artisan.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,14 @@ class Meta:
4343
'first_name', 'last_name', 'profile_picture'
4444
))
4545
job_category = fields.Method(serialize='show_category')
46+
bank_accounts = fields.Nested(
47+
'WithdrawalAccountSchema',
48+
only=(
49+
'account_name', 'account_number',
50+
'bank_name', 'bank_code'
51+
),
52+
many=True
53+
)
4654

4755
@pre_load
4856
def preformat_data(self, data, *args, **kwargs):

0 commit comments

Comments
 (0)