Optimizing the Digital Procurement Flow: Implementation of PR, RFQ, PO, and GRN
T
Kembali ke Blog

Optimizing the Digital Procurement Flow: Implementation of PR, RFQ, PO, and GRN

Tutorial
Tim Pilar Inovasi 02 Jul 2026 16 min baca 3,748 kata 240
This article discusses a practical guide to implementing a digital procurement flow (PR, RFQ, PO, GRN) for operational efficiency. Learn concrete steps, technologies, and best practices for a transparent and accountable procurement system.

Many organizations, especially in the healthcare sector such as hospitals and clinics, are still grappling with procurement processes that are manual, error-prone, and time-consuming. Imagine an operations manager having to approve hundreds of paper purchase requests every month, or a procurement team spending precious hours manually comparing quotes. Data from Supply Chain Management Review shows that manual procurement processes can increase operational costs by up to 15-20% due to inefficiencies and lack of visibility. This problem is not just about cost, but also accountability, transparency, and speed of response to critical needs, especially for medical inventory or pharmaceuticals. This article will guide you in depth on how to implement an effective digital procurement workflow, covering Purchase Requisition (PR), Request for Quotation (RFQ), Purchase Order (PO), through to Goods Receipt Note (GRN). We will discuss the basic concepts, technical implementation details with concrete examples using modern technology, as well as best practices to ensure your procurement system is efficient, transparent, and capable of optimally supporting your business operations.

Basic Concepts of Digital Procurement Workflow: PR, RFQ, PO, GRN

The procurement workflow is a series of structured steps followed by an organization to obtain goods or services. In a digital context, this workflow is automated to improve efficiency, accuracy, and transparency. The four main pillars we will discuss are Purchase Requisition (PR), Request for Quotation (RFQ), Purchase Order (PO), and Goods Receipt Note (GRN).

Purchase Requisition (PR) is an internal document created by a department or individual that needs goods or services. The PR serves as the initial authorization to start the procurement process. For example, the nursing department at a hospital submits a PR for 500 units of sterile syringes and 20 liters of disinfectant. This PR must include details such as the type of goods, quantity, specifications, required date, and reason for purchase. Without an approved PR, the procurement process must not proceed, ensuring that every purchase has a clear justification and has been approved by the authorized party.

After the PR is approved, the next step is the Request for Quotation (RFQ). An RFQ is a document sent to several potential vendors to request price quotes and delivery terms for the required goods or services. In the hospital case, the procurement team would send an RFQ to several medical device or pharmaceutical distributors for the syringes and disinfectant mentioned in the PR. The RFQ must be detailed, including technical specifications, quantity, delivery schedule, warranty requirements, and bid evaluation criteria. The goal is to obtain the best price and the most favorable terms through competition among vendors, so that the organization can make an informed and economical purchasing decision.

Based on the evaluation of RFQ bids, the procurement team will select the best vendor and issue a Purchase Order (PO). A PO is an official document that serves as a legal contract between the buyer and the seller, binding both parties. The PO lists complete details such as vendor name, description of goods/services, quantity, unit price, total price, payment terms, and delivery schedule. For our example, the PO would be sent to the selected distributor for 500 syringes and 20 liters of disinfectant at the agreed price and terms. A clear PO prevents misunderstandings and ensures that the goods or services received match expectations.

Finally, when the goods are received, a Goods Receipt Note (GRN) is created. The GRN is an internal document that records the receipt of goods. The warehouse or logistics team will verify the received goods against the PO to ensure the quantity and quality match. If 500 syringes and 20 liters of disinfectant arrive, the officer will record them in the GRN. The GRN is very important for accounting and inventory purposes, as it marks the point at which ownership of the goods transfers and the liability to the vendor is officially recognized. It also serves as the basis for the payment process and stock updates in the inventory management system.

Technical Implementation Details of a Digital Procurement System

Implementing an effective digital procurement system requires choosing the right technology and a solid architecture. For the context of Nugroho Setiawan, who has experience in SIMRS and ERP, we will assume the use of a modern stack such as Laravel 11.x for the backend, Vue.js 3 for the frontend (optional, or Blade/Livewire), and PostgreSQL 16 as the database. Integration with other systems such as SIMRS or accounting systems is also a crucial consideration.

At the database level, we need main tables to represent each entity in the workflow. For example, the purchase_requisitions table will store PR data, rfqs for RFQs, purchase_orders for POs, and goods_receipt_notes for GRNs. Each of these tables will have a one-to-many or one-to-one relationship with detail item tables (for example, pr_items, rfq_items, po_items, grn_items). It is also important to have vendors, products/services, and users tables for authorization and audit trails. This structure enables comprehensive data tracking from the beginning to the end of the process. For example, each po_item must have a reference to the pr_item that initiated it, and grn_item must refer to the relevant po_item.

For workflow state management, we can use a status column on each document (for example, status in the purchase_requisitions table can be 'Draft', 'Pending Approval', 'Approved', 'Rejected', 'Converted to RFQ', 'Cancelled'). When a PR is approved, its status can change to 'Approved', and the system can automatically trigger the creation of an RFQ. Likewise, when a PO is created from an RFQ, the RFQ status can change to 'PO Issued'. Laravel 11.x provides powerful model events features to automate status changes or trigger other actions after an entity is saved or updated. For example, after a PO is created, the system can automatically send email notifications to the vendor and the warehouse team.

The authorization and authentication aspects are very important. Using Laravel Sanctum or Laravel Passport for API authentication will ensure that only authorized users can perform certain actions (for example, only managers can approve PRs). Authorization policies (Policies) in Laravel can define who can view, create, update, or delete each type of document. For example, a user with the "Warehouse Staff" role can only create GRNs, while a "Procurement Manager" can create RFQs and POs. An audit trail must also be implemented by recording every important change to a document, who made it, and when, using a separate table or a feature such as Laravel Auditing.

Integration with external systems, such as the inventory system in the SIMRS or the accounting module in the ERP, will be done via API. For example, when a GRN is created, the procurement system must call the SIMRS API to update the inventory stock of medicines or medical devices. We can use the Guzzle HTTP client in Laravel to make API calls to external endpoints. If the external system uses standards such as FHIR R4 or HL7 v2.5.1 (for SIMRS), make sure your procurement system is capable of producing or consuming payloads in those formats. For example, stock updates could be sent as an FHIR Observation message or an HL7 ORU^R01. It is also important to implement retry and logging mechanisms for API calls to handle connection failures or unexpected responses.

Code Implementation Example: PR Validation and PO Creation

This section will present an example of PHP code using the Laravel 11.x framework. We will focus on two key scenarios: (1) validation and storage of a Purchase Requisition (PR), and (2) the mechanism for creating a Purchase Order (PO) from an approved RFQ. This code is designed to demonstrate best practices in enterprise application development, including robust validation and the use of database transactions.

Example 1: Controller for Storing a Purchase Requisition

The code below shows the store method in PurchaseRequisitionController. It receives data from an HTTP request, performs strict validation, and then saves the PR along with its items to the database within a transaction. The use of a transaction (DB::transaction) is very important to ensure data integrity: if any PR item fails to save, the entire PR will not be saved.

<?phpnamespace App\Http\Controllers;use App\Models\PurchaseRequisition;use App\Models\PurchaseRequisitionItem;use Illuminate\Http\Request;use Illuminate\Support\Facades\DB;use Illuminate\Support\Facades\Auth;use Illuminate\Validation\ValidationException;class PurchaseRequisitionController extends Controller{    public function store(Request $request)    {        try {            $validatedData = $request->validate([                'department_id' => 'required|exists:departments,id',                'required_date' => 'required|date|after_or_equal:today',                'justification' => 'required|string|max:500',                'items' => 'required|array|min:1',                'items.*.product_id' => 'required|exists:products,id',                'items.*.quantity' => 'required|integer|min:1',                'items.*.unit_price' => 'nullable|numeric|min:0', // Optional, can be filled later            ]);            DB::transaction(function () use ($validatedData) {                $pr = PurchaseRequisition::create([                    'department_id' => $validatedData['department_id'],                    'user_id' => Auth::id(), // User yang membuat PR                    'required_date' => $validatedData['required_date'],                    'justification' => $validatedData['justification'],                    'status' => 'Pending Approval', // Status awal                ]);                foreach ($validatedData['items'] as $itemData) {                    $pr->items()->create([                        'product_id' => $itemData['product_id'],                        'quantity' => $itemData['quantity'],                        'unit_price' => $itemData['unit_price'] ?? 0,                    ]);                }            });            return response()->json(['message' => 'Purchase Requisition created successfully.'], 201);        } catch (ValidationException $e) {            return response()->json(['errors' => $e->errors()], 422);        } catch (\Exception $e) {            // Log the error for debugging            \Log::error("Failed to create PR: " . $e->getMessage());            return response()->json(['message' => 'Failed to create Purchase Requisition.'], 500);        }    }}

Explanation: Validation ensures that all required data is present and in the correct format. The user_id column is automatically filled with the ID of the currently logged-in user. The initial status 'Pending Approval' indicates that the PR is ready to be reviewed by the manager. The use of DB::transaction guarantees that if there is a failure while saving items, the entire process will be rolled back, maintaining database consistency.

Example 2: Mechanism for Creating a Purchase Order from an RFQ

After the RFQ is approved and a vendor is selected, a PO can be created. This code shows how the PO and its items are created based on the approved RFQ. It assumes that the RFQ already has quotation items from the selected vendor.

<?phpnamespace App\Http\Controllers;use App\Models\RequestForQuotation;use App\Models\PurchaseOrder;use App\Models\PurchaseOrderItem;use Illuminate\Http\Request;use Illuminate\Support\Facades\DB;use Illuminate\Support\Facades\Auth;class PurchaseOrderController extends Controller{    public function createFromRfq(Request $request, RequestForQuotation $rfq)    {        // Ensure the RFQ has been approved and has a selected vendor        if ($rfq->status !== 'Approved' || !$rfq->selected_vendor_id) {            return response()->json(['message' => 'RFQ is not approved or vendor not selected.'], 400);        }        try {            DB::transaction(function () use ($rfq) {                // Create a new Purchase Order                $po = PurchaseOrder::create([                    'rfq_id' => $rfq->id,                    'vendor_id' => $rfq->selected_vendor_id,                    'user_id' => Auth::id(), // User who creates the PO                    'order_date' => now(),                    'delivery_date' => $rfq->expected_delivery_date, // Take from RFQ                    'total_amount' => 0, // Will be calculated from items                    'status' => 'Issued',                ]);                $totalAmount = 0;                foreach ($rfq->items as $rfqItem) {                    // Assume rfqItem has price_from_selected_vendor                    $unitPrice = $rfqItem->price_from_selected_vendor;                    $lineTotal = $rfqItem->quantity * $unitPrice;                    $po->items()->create([                        'product_id' => $rfqItem->product_id,                        'quantity' => $rfqItem->quantity,                        'unit_price' => $unitPrice,                        'total_price' => $lineTotal,                        'pr_item_id' => $rfqItem->pr_item_id, // Link back to PR item                    ]);                    $totalAmount += $lineTotal;                }                // Update PO total amount                $po->update(['total_amount' => $totalAmount]);                // Update RFQ status                $rfq->update(['status' => 'PO Issued']);            });            return response()->json(['message' => 'Purchase Order created successfully from RFQ.'], 201);        } catch (\Exception $e) {            \Log::error("Failed to create PO from RFQ {$rfq->id}: " . $e->getMessage());            return response()->json(['message' => 'Failed to create Purchase Order.'], 500);        }    }}

Explanation: This method accepts an existing RFQ object. Initial validation ensures that the RFQ has indeed been approved and has a selected vendor. The PO is created, and its items are filled based on the items in the RFQ, including the prices agreed upon with the selected vendor. The RFQ status is then updated to 'PO Issued'. Again, a database transaction is used to ensure data consistency. This is an example of how one stage in the workflow triggers and updates the status of the previous stage, creating an integrated flow.

Example Payload and Integration Error Handling

In an integrated digital procurement system, data exchange between systems is common. For example, after a Goods Receipt Note (GRN) is created, the inventory system or SIMRS needs to be updated. We will present an example JSON payload for stock updates and how to handle potential errors that arise during the integration process.

Example JSON Payload for Inventory Stock Update (from GRN to SIMRS)

When a warehouse officer records the receipt of 100 units of "Paracetamol 500mg" with a specific batch number and expiration date, the procurement system will send a JSON payload to the SIMRS API. This payload must follow the schema agreed upon by both systems. In the context of a SIMRS that may adopt the FHIR standard, this payload could be interpreted as a FHIR Bundle containing Observations or InventoryReport, but for simplicity, we use a common custom JSON format.

{  "transaction_id": "GRN-20231108-001",  "grn_date": "2023-11-08T10:30:00Z",  "po_reference": "PO-20231025-005",  "items": [    {      "product_id": "PROD-00123",      "product_name": "Paracetamol 500mg Tablet",      "quantity_received": 100,      "unit_of_measure": "tablet",      "batch_number": "BATCH-P500-202310",      "expiry_date": "2025-12-31",      "storage_location": "GUDANG-FARMASI-A1"    },    {      "product_id": "PROD-00456",      "product_name": "Masker N95",      "quantity_received": 50,      "unit_of_measure": "pcs",      "batch_number": "BATCH-MN95-202309",      "expiry_date": "2026-09-30",      "storage_location": "GUDANG-MEDIS-B3"    }  ],  "received_by": {    "user_id": "USR-007",    "user_name": "Budi Santoso"  }}

The payload above provides all the information needed by the SIMRS to update its inventory, including transaction identification, product details, quantity, batch number, expiration date, storage location, and who received it. Consistency in this format is crucial for smooth integration.

Example Error Messages and How to Handle Them

Although we have carefully designed the system, integration failures can occur. One common example of an error is a validation failure on the API receiver side or a connectivity issue. The following is an example of an error response from SIMRS:

{  "status": 400,  "code": "VALIDATION_ERROR",  "message": "Payload validation failed for inventory update.",  "errors": [    {      "field": "items[0].expiry_date",      "code": "INVALID_DATE_FORMAT",      "description": "Expiry date '2025-12-31T00:00:00Z' is not in expected 'YYYY-MM-DD' format."    },    {      "field": "items[1].product_id",      "code": "PRODUCT_NOT_FOUND",      "description": "Product ID 'PROD-00456' not found in inventory master data."    }  ]}

Handling this error must be done systematically on the sender side (the procurement system). When an error response like this is received, the procurement system must:

  1. Log Error: Record the error details (status code, message, specific error) in the system log. This is important for auditing and debugging.
  2. Notification: Send an automatic notification (for example, email or Slack message) to the IT team or the responsible operations manager, informing them of the integration failure.
  3. Retry Mechanism: For temporary errors (for example, network connection issues or timeouts), implement a retry mechanism with an exponential backoff strategy. Do not immediately retry many times in a short period.
  4. Transaction Status: Update the GRN status in the procurement system to 'Integration Failed' or 'Awaiting Resynchronization', not 'Completed'. This indicates that the process has not been completed.
  5. Message Queue: For more complex systems with high load, use a message queue (such as RabbitMQ or Apache Kafka). When a GRN is created, the stock update message is placed into the queue. A worker/consumer will take this message and try to send it to SIMRS. If it fails, the message can be sent back to the queue or to a 'dead-letter' queue for manual review. This decouples the process and increases resilience.
  6. Monitoring Dashboard: Provide a dashboard where managers can view the integration status, identify failed transactions, and possibly trigger a manual retry after the issue is resolved.

With a comprehensive error handling strategy, the system can operate more stably and reduce the negative impact of integration failures.

Best Practices for Procurement Workflow Implementation

  1. Define Roles and Authorization Clearly: Before starting development, map each role (for example, PR Requester, PR Approver, Procurement Manager, Warehouse Officer) and determine exactly what actions they are allowed to perform at each stage of the workflow. This will be the basis for authorization configuration in your system, such as using Role-Based Access Control (RBAC) in Laravel. Clarity of roles reduces the risk of misuse and speeds up the approval process.
  2. Automate Notifications and Reminders: Leverage the system to send automatic notifications (email, SMS, in-app notifications) on every status change or when action is required. For example, when a PR is submitted, the relevant manager receives a notification for approval. If a PR or PO is pending approval for more than X hours, send an automatic reminder. This automation significantly reduces cycle time and ensures no step is missed.
  3. Implement a Comprehensive Audit Trail: Every action and change to PR, RFQ, PO, and GRN documents must be recorded, including who performed it, when, and what changes occurred. This feature is crucial for accountability, dispute resolution, and regulatory compliance. For example, in SIMRS, the change history for medicine procurement is an important requirement for internal and external audits.
  4. Integrate with Accurate Master Data: Ensure the procurement system is tightly integrated with accurate master data for products/services, vendors, and departments. Consistent data prevents input errors, data duplication, and ensures that the information used throughout the workflow is the latest and correct. Always validate input against existing master data.
  5. Strong and Dynamic Input Validation: Apply strict validation to every data input. For example, quantity must be a positive number, expiration dates must be in the future, and vendors must be registered. In addition, consider dynamic validation based on document status (for example, a PO that is already 'Issued' can no longer have its items changed). This validation prevents dirty data from entering the system and reduces correction work later.
  6. Provide Real-time Reports and Analytics: The procurement system must be able to generate reports and dashboards that provide real-time visibility into procurement status, vendor performance, and spending. For example, reports on the average PR approval time, the percentage of POs delivered on time, or spending analysis per department. This data is invaluable for strategic decision-making and identifying areas for improvement.
  7. Plan for Scalability and Security: Design the system with scalability in mind. As the organization grows, the volume of procurement transactions will also increase. Ensure the database and application architecture can handle that load. On the security side, apply best practices such as data encryption (in transit and at rest), regular vulnerability testing, and application of the least privilege principle for system access. Procurement data is often sensitive, so its security is a top priority.

FAQ About Digital Procurement Workflow Implementation

  1. What is the main difference between PR and PO?

    PR (Purchase Requisition) is an internal document created by a department to request the purchase of goods or services, serving as initial authorization. Meanwhile, PO (Purchase Order) is an external document sent to the selected vendor, serving as a legally binding contract between buyer and seller. PR precedes PO and is the first step in starting the official procurement process.

  2. How do you manage multi-level approval for PR or PO?

    Multi-level approval can be implemented by defining an approval hierarchy based on transaction value or item type. For example, a PR below Rp 5 million may only need one department manager approval, while a PR above Rp 50 million may need approval from the finance director and operations director. In technical implementation, this can be managed with an approval flow configuration table and document status that records who has approved and who is next.

  3. Can this system be integrated with an existing accounting or ERP system?

    Yes, absolutely. Integration with an existing accounting system or ERP module is one of the main benefits of procurement digitalization. Generally, integration is done through an API (Application Programming Interface). Approved PO data can be sent to the accounting module to create spending commitments, and GRN data can trigger recording of accounts payable to vendors and update the inventory ledger. Make sure you understand the data format and API protocol of the system to be integrated.

  4. How do you ensure the security of sensitive procurement data?

    Data security is a priority. Apply data encryption both when stored (data at rest) and when transmitted (data in transit) using SSL/TLS. Use strong authentication and authorization systems (for example, OAuth2 or JWT) with the least privilege principle, meaning users only have access to the data and functions they truly need. Conduct regular security audits, penetration testing, and ensure all system components (server, database, application) are always updated with the latest security patches.

  5. What are the common challenges when implementing this workflow and how to overcome them?

    Common challenges include resistance to change from users, difficulty in defining clear processes, integration with legacy systems, and inaccurate master data. Overcoming them requires strong change management, comprehensive user training, involving stakeholders from the start, and performing master data cleansing and standardization before migration. Start with a small pilot project and scale up gradually.

  6. How long does it take to implement a system like this?

    Implementation time varies greatly depending on the complexity of the organization, the number of departments, transaction volume, and the desired level of integration. For a medium-scale organization with relatively standard processes, basic implementation (PR, PO, GRN) can take 3-6 months. If it involves RFQ, complex multi-level approvals, and deep integration with many external systems, it can take 6-12 months or more. An incremental (agile) approach is often more effective.

Implementing a digital procurement workflow from PR to GRN is not just about adopting new technology, but a fundamental transformation that brings efficiency, transparency, and accountability to your operations. With the concrete technical guidance and best practices that have been discussed, you now have a roadmap to start or improve your procurement system. Remember, investing in the right system will minimize operational costs, reduce the risk of errors, and free up your valuable resources to focus on innovation and core services. If you are a Hospital IT Manager, clinic owner, or operations manager ready to take your procurement system to the next level, our team at Nugroho Setiawan is ready to help. We have deep experience in developing ERP, SIMRS, and system integration solutions tailored to your organization's unique needs. Don't hesitate to contact us for a consultation and find out how we can be your technology partner.

Terakhir diperbarui 17 Oct 2026

Komentar

Komentar ditinjau sebelum tampil.

Belum ada komentar. Jadilah yang pertama!