Change Working status to Available

This commit is contained in:
Keannu Bernasol 2023-12-16 15:00:13 +08:00
parent 8abf689544
commit 9e16bda918
6 changed files with 110 additions and 33 deletions

View file

@ -0,0 +1,23 @@
# Generated by Django 4.2.7 on 2023-12-16 06:53
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('equipments', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='equipmentinstance',
name='status',
field=models.CharField(choices=[('Available', 'Available'), ('Broken', 'Broken'), ('Borrowed', 'Borrowed')], default='Available', max_length=20),
),
migrations.AlterField(
model_name='historicalequipmentinstance',
name='status',
field=models.CharField(choices=[('Available', 'Available'), ('Broken', 'Broken'), ('Borrowed', 'Borrowed')], default='Available', max_length=20),
),
]

View file

@ -24,13 +24,13 @@ class Equipment(models.Model):
class EquipmentInstance(models.Model): class EquipmentInstance(models.Model):
EQUIPMENT_INSTANCE_STATUS_CHOICES = ( EQUIPMENT_INSTANCE_STATUS_CHOICES = (
('Working', 'Working'), ('Available', 'Available'),
('Broken', 'Broken'), ('Broken', 'Broken'),
('Borrowed', 'Borrowed'), ('Borrowed', 'Borrowed'),
) )
equipment = models.ForeignKey(Equipment, on_delete=models.CASCADE) equipment = models.ForeignKey(Equipment, on_delete=models.CASCADE)
status = models.CharField( status = models.CharField(
max_length=20, choices=EQUIPMENT_INSTANCE_STATUS_CHOICES, default='PENDING') max_length=20, choices=EQUIPMENT_INSTANCE_STATUS_CHOICES, default='Available')
remarks = models.TextField(max_length=512, null=True) remarks = models.TextField(max_length=512, null=True)
date_added = models.DateTimeField(default=now, editable=False) date_added = models.DateTimeField(default=now, editable=False)
last_updated = models.DateTimeField(auto_now=True, editable=False) last_updated = models.DateTimeField(auto_now=True, editable=False)
@ -46,12 +46,12 @@ def create_superuser(sender, **kwargs):
EQUIPMENT, CREATED = Equipment.objects.get_or_create( EQUIPMENT, CREATED = Equipment.objects.get_or_create(
name="Pyrex Beaker", description="", category="Glassware") name="Pyrex Beaker", description="", category="Glassware")
EQUIPMENT_INSTANCE, CREATED = EquipmentInstance.objects.get_or_create( EQUIPMENT_INSTANCE, CREATED = EquipmentInstance.objects.get_or_create(
equipment=EQUIPMENT, status="Working", remarks="First beaker of equipment tracker!") equipment=EQUIPMENT, status="Available", remarks="First beaker of equipment tracker!")
EQUIPMENT, CREATED = Equipment.objects.get_or_create( EQUIPMENT, CREATED = Equipment.objects.get_or_create(
name="Bunsen Burner", description="", category="Miscellaneous") name="Bunsen Burner", description="", category="Miscellaneous")
EQUIPMENT_INSTANCE, CREATED = EquipmentInstance.objects.get_or_create( EQUIPMENT_INSTANCE, CREATED = EquipmentInstance.objects.get_or_create(
equipment=EQUIPMENT, status="Working", remarks="First bunsen burner of equipment tracker!") equipment=EQUIPMENT, status="Available", remarks="First bunsen burner of equipment tracker!")
EQUIPMENT, CREATED = Equipment.objects.get_or_create( EQUIPMENT, CREATED = Equipment.objects.get_or_create(
name="Microscope", description="", category="Miscellaneous") name="Microscope", description="", category="Miscellaneous")
EQUIPMENT_INSTANCE, CREATED = EquipmentInstance.objects.get_or_create( EQUIPMENT_INSTANCE, CREATED = EquipmentInstance.objects.get_or_create(
equipment=EQUIPMENT, status="Working", remarks="First microscope of equipment tracker!") equipment=EQUIPMENT, status="Available", remarks="First microscope of equipment tracker!")

View file

@ -159,12 +159,12 @@ class EquipmentInstanceSerializer(serializers.HyperlinkedModelSerializer):
equipments=instance, resolved=False).first() equipments=instance, resolved=False).first()
# If there is one # If there is one
if associated_breakage_report: if associated_breakage_report:
# Check if all the equipments of the currently associated BreakageReport are "Working" # Check if all the equipments of the currently associated BreakageReport are "Available"
all_working = all( all_available = all(
eq.status == 'Working' for eq in associated_breakage_report.equipments.all()) eq.status == 'Available' for eq in associated_breakage_report.equipments.all())
# If all the equipments are "Working", set Breakage Report to be resolved (resolved=True) # If all the equipments are "Available", set Breakage Report to be resolved (resolved=True)
if all_working: if all_available:
associated_breakage_report.resolved = True associated_breakage_report.resolved = True
associated_breakage_report.save() associated_breakage_report.save()

View file

@ -1020,6 +1020,37 @@ paths:
schema: schema:
$ref: '#/components/schemas/Transaction' $ref: '#/components/schemas/Transaction'
description: '' description: ''
patch:
operationId: api_v1_transactions_partial_update
parameters:
- in: path
name: id
schema:
type: integer
description: A unique integer value identifying this transaction.
required: true
tags:
- api
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatchedTransaction'
application/x-www-form-urlencoded:
schema:
$ref: '#/components/schemas/PatchedTransaction'
multipart/form-data:
schema:
$ref: '#/components/schemas/PatchedTransaction'
security:
- jwtAuth: []
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/Transaction'
description: ''
components: components:
schemas: schemas:
Activation: Activation:
@ -1106,6 +1137,7 @@ components:
type: string type: string
description: description:
type: string type: string
maxLength: 512
category: category:
$ref: '#/components/schemas/CategoryEnum' $ref: '#/components/schemas/CategoryEnum'
last_updated: last_updated:
@ -1121,7 +1153,6 @@ components:
readOnly: true readOnly: true
required: required:
- date_added - date_added
- description
- id - id
- last_updated - last_updated
- last_updated_by - last_updated_by
@ -1144,6 +1175,7 @@ components:
$ref: '#/components/schemas/StatusEnum' $ref: '#/components/schemas/StatusEnum'
remarks: remarks:
type: string type: string
maxLength: 512
last_updated: last_updated:
type: string type: string
format: date-time format: date-time
@ -1367,6 +1399,7 @@ components:
type: string type: string
description: description:
type: string type: string
maxLength: 512
category: category:
$ref: '#/components/schemas/CategoryEnum' $ref: '#/components/schemas/CategoryEnum'
last_updated: last_updated:
@ -1398,6 +1431,7 @@ components:
$ref: '#/components/schemas/StatusEnum' $ref: '#/components/schemas/StatusEnum'
remarks: remarks:
type: string type: string
maxLength: 512
last_updated: last_updated:
type: string type: string
format: date-time format: date-time
@ -1409,6 +1443,26 @@ components:
type: string type: string
format: date-time format: date-time
readOnly: true readOnly: true
PatchedTransaction:
type: object
properties:
id:
type: integer
readOnly: true
borrower:
type: integer
teacher:
type: integer
equipments:
type: array
items:
type: integer
transaction_status:
$ref: '#/components/schemas/TransactionStatusEnum'
timestamp:
type: string
format: date-time
readOnly: true
SendEmailReset: SendEmailReset:
type: object type: object
properties: properties:
@ -1444,12 +1498,12 @@ components:
- new_username - new_username
StatusEnum: StatusEnum:
enum: enum:
- Working - Available
- Broken - Broken
- Borrowed - Borrowed
type: string type: string
description: |- description: |-
* `Working` - Working * `Available` - Available
* `Broken` - Broken * `Broken` - Broken
* `Borrowed` - Borrowed * `Borrowed` - Borrowed
TokenObtainPair: TokenObtainPair:
@ -1500,11 +1554,8 @@ components:
readOnly: true readOnly: true
borrower: borrower:
type: integer type: integer
nullable: true
teacher: teacher:
type: string type: integer
format: uri
nullable: true
equipments: equipments:
type: array type: array
items: items:
@ -1516,7 +1567,10 @@ components:
format: date-time format: date-time
readOnly: true readOnly: true
required: required:
- borrower
- equipments
- id - id
- teacher
- timestamp - timestamp
- transaction_status - transaction_status
TransactionStatusEnum: TransactionStatusEnum:

View file

@ -99,7 +99,7 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer):
equipments = validated_data['equipments'] equipments = validated_data['equipments']
for equipment in equipments: for equipment in equipments:
existing__pending_transactions = Transaction.objects.filter( existing__pending_transactions = Transaction.objects.filter(
equipments=equipment, status__in=['Pending', 'Approved', 'Borrowed', 'With Breakages: Pending Resolution']) equipments=equipment, transaction_status__in=['Pending', 'Approved', 'Borrowed', 'With Breakages: Pending Resolution'])
if existing__pending_transactions.exists(): if existing__pending_transactions.exists():
raise serializers.ValidationError( raise serializers.ValidationError(
f"Cannot add Equipment #{equipment.id}. It is still part of a non-finalized transaction") f"Cannot add Equipment #{equipment.id}. It is still part of a non-finalized transaction")
@ -110,13 +110,13 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer):
user = self.context['request'].user user = self.context['request'].user
# If user is not a teacher or a technician, forbid them from changing the status of a transaction # If user is not a teacher or a technician, forbid them from changing the status of a transaction
if not user.is_teacher and not user.technician and 'transaction_status' in validated_data and validated_data['transaction_status'] != instance.status: if not user.is_teacher and not user.is_technician and 'transaction_status' in validated_data and validated_data['transaction_status'] != instance.transaction_status:
raise serializers.ValidationError( raise serializers.ValidationError(
"You are not a teacher or technician. You do not have permission to change the status of transactions" "You are not a teacher or technician. You do not have permission to change the status of transactions"
) )
# If user is not a teacher, forbid them from changing the status of a transaction # If user is not a teacher, forbid them from changing the status of a transaction
if not user.is_teacher and 'transaction_status' in validated_data and validated_data['transaction_status'] != instance.status: if not user.is_teacher and 'transaction_status' in validated_data and validated_data['transaction_status'] != instance.transaction_status:
raise serializers.ValidationError( raise serializers.ValidationError(
"You do not have permission to change the status of a transaction" "You do not have permission to change the status of a transaction"
) )
@ -128,7 +128,7 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer):
# For already finalized/done transactions (Rejected or Finalized ones) # For already finalized/done transactions (Rejected or Finalized ones)
# Do not allow any changes to already finalized transactions # Do not allow any changes to already finalized transactions
if instance.status in ['Rejected', 'Finalized']: if instance.transaction_status in ['Rejected', 'Finalized']:
raise serializers.ValidationError( raise serializers.ValidationError(
"Unable to update rejected or finalized transaction. Please create a new one" "Unable to update rejected or finalized transaction. Please create a new one"
) )
@ -138,7 +138,7 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer):
# For Pending transactions # For Pending transactions
# If not changing to Approved or Rejected, throw an error # If not changing to Approved or Rejected, throw an error
if instance.status == 'Pending' and validated_data['transaction_status'] != 'Approved' or validated_data['transaction_status'] != 'Rejected': if instance.transaction_status == "Pending" and (validated_data['transaction_status'] != "Approved" or validated_data['transaction_status'] != "Rejected"):
raise serializers.ValidationError( raise serializers.ValidationError(
"A pending transaction can only change to Approved or Rejected" "A pending transaction can only change to Approved or Rejected"
) )
@ -146,7 +146,7 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer):
# For Approved transactions, # For Approved transactions,
# If not changing to Borrowed or Cancelled, throw an error # If not changing to Borrowed or Cancelled, throw an error
# Already approved transactions can only be moved to Borrowed or Cancelled # Already approved transactions can only be moved to Borrowed or Cancelled
if instance.status == 'Approved' and validated_data['transaction_status'] != 'Borrowed' or validated_data != 'Cancelled': if instance.transaction_status == "Approved" and (validated_data['transaction_status'] != "Borrowed" or validated_data != "Cancelled"):
raise serializers.ValidationError( raise serializers.ValidationError(
"An already approved transaction can only changed to Borrowed (On borrow) or Cancelled" "An already approved transaction can only changed to Borrowed (On borrow) or Cancelled"
) )
@ -154,7 +154,7 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer):
# For Borrowed transactions, # For Borrowed transactions,
# If not changing to returned, throw an error # If not changing to returned, throw an error
# Borrowed transactions that can only be changed to returned, pending checking for broken items # Borrowed transactions that can only be changed to returned, pending checking for broken items
if instance.status == 'Borrowed' and validated_data['transaction_status'] != 'Finalized' or validated_data != 'With Breakages: Pending Resolution': if instance.transaction_status == "Borrowed" and (validated_data['transaction_status'] != "Finalized" or validated_data != "With Breakages: Pending Resolution"):
raise serializers.ValidationError( raise serializers.ValidationError(
"A borrowed transaction can only changed to status of Finalized or With Breakages: Pending Resolution" "A borrowed transaction can only changed to status of Finalized or With Breakages: Pending Resolution"
) )
@ -162,7 +162,7 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer):
# For Return: Pending Checking transactions, # For Return: Pending Checking transactions,
# If not changing to With Breakages: Pending Resolution or Finalized, throw an error # If not changing to With Breakages: Pending Resolution or Finalized, throw an error
# Returned transactions can only be finalized without any issues or be marked as with breakages # Returned transactions can only be finalized without any issues or be marked as with breakages
if instance.status == 'Returned: Pending Checking' and validated_data['transaction_status'] != 'Finalized' or validated_data != 'With Breakages: Pending Resolution': if instance.transaction_status == "Returned: Pending Checking" and (validated_data['transaction_status'] != "Finalized" or validated_data != "With Breakages: Pending Resolution"):
raise serializers.ValidationError( raise serializers.ValidationError(
"A borrowed transaction can only changed to status of Finalized or With Breakages: Pending Resolution" "A borrowed transaction can only changed to status of Finalized or With Breakages: Pending Resolution"
) )
@ -170,27 +170,27 @@ class TransactionSerializer(serializers.HyperlinkedModelSerializer):
# For transactions with pending breakage resolutions, # For transactions with pending breakage resolutions,
# Do not allow updating of status. It should be updated within its respective breakage report # Do not allow updating of status. It should be updated within its respective breakage report
# If it has been resolved there, this field will automatically update to Finalized # If it has been resolved there, this field will automatically update to Finalized
if instance.status == 'With Breakages: Pending Resolution': if instance.transaction_status == "With Breakages: Pending Resolution":
raise serializers.ValidationError( raise serializers.ValidationError(
"A transaction with pending breakage resolutions must be updated or resolved in its respective breakage report" "A transaction with pending breakage resolutions must be updated or resolved in its respective breakage report"
) )
# If there are no issues and a transaction changes from Approved to Borrowed, label the selected equipment's statuses as Borrowed # If there are no issues and a transaction changes from Approved to Borrowed, label the selected equipment's statuses as Borrowed
if instance.status == 'Approved' and validated_data['transaction_status'] == 'Borrowed': if instance.transaction_status == "Approved" and validated_data['transaction_status'] == "Borrowed":
equipments = validated_data.get('equipments', []) equipments = validated_data.get('equipments', [])
for equipment in equipments: for equipment in equipments:
equipment.status = 'Borrowed' equipment.transaction_status = 'Borrowed'
equipment.save() equipment.save()
return super().update(validated_data) return super().update(validated_data)
# If the transaction changes from Borrowed to Finalized and there are no breakages, label the selected equipment's statuses as Working again from Borrowed # If the transaction changes from Borrowed to Finalized and there are no breakages, label the selected equipment's statuses as Available again from Borrowed
if instance.status == 'Borrowed' and validated_data['transaction_status'] == 'Finalized': if instance.transaction_status == "Borrowed" and validated_data['transaction_status'] == "Finalized":
equipments = validated_data.get('equipments', []) equipments = validated_data.get('equipments', [])
for equipment in equipments: for equipment in equipments:
equipment.status = 'Working' equipment.transaction_status = 'Available'
equipment.save() equipment.save()
return super().update(validated_data) return super().update(validated_data)
# If the transaction changes from Borrowed to With Breakages, we create a Breakage Report instance # If the transaction changes from Borrowed to With Breakages, we create a Breakage Report instance
if instance.status == 'Borrowed' and validated_data['transaction_status'] == 'Finalized': if instance.transaction_status == "Borrowed" and validated_data['transaction_status'] == "Finalized":
BreakageReport.objects.create( BreakageReport.objects.create(
transaction=instance, transaction=instance,
equipments=instance.equipments.all(), equipments=instance.equipments.all(),

View file

@ -7,7 +7,7 @@ from .models import Transaction
class TransactionViewSet(viewsets.ModelViewSet): class TransactionViewSet(viewsets.ModelViewSet):
# Only allow GET, POST/CREATE # Only allow GET, POST/CREATE
# Transactions cannot be deleted # Transactions cannot be deleted
http_method_names = ['get', 'post'] http_method_names = ['get', 'post', 'patch']
permission_classes = [IsAuthenticated] permission_classes = [IsAuthenticated]
serializer_class = TransactionSerializer serializer_class = TransactionSerializer
queryset = Transaction.objects.all() queryset = Transaction.objects.all()