fix(sync): make transaction creation idempotent (#38)
## Summary - When a transaction ID is provided during sync, check if it already exists before creating - If it exists, return the existing transaction with 200 status instead of failing with duplicate key error - Prevents duplicate transactions when sync retries occur due to network issues ## Test plan - [x] Attempt to create a transaction with a specific ID - [x] Attempt to create another transaction with the same ID - [x] Verify the second request returns the existing transaction instead of an error
This commit is contained in:
parent
6f42b91585
commit
3cbe0a7879
|
|
@ -36,6 +36,21 @@ class TransactionSyncController extends Controller
|
|||
$labelIds = $data['label_ids'] ?? [];
|
||||
unset($data['label_ids']);
|
||||
|
||||
// If ID is provided, check if transaction already exists (idempotent create)
|
||||
if (isset($data['id'])) {
|
||||
$existing = Transaction::query()
|
||||
->where('id', $data['id'])
|
||||
->where('user_id', $request->user()->id)
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
// Transaction already exists, return it as success (idempotent)
|
||||
return response()->json([
|
||||
'data' => $existing->load('labels:id,name,color'),
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
|
||||
// Create transaction with provided ID if available
|
||||
$transaction = new Transaction([
|
||||
...$data,
|
||||
|
|
|
|||
|
|
@ -58,6 +58,6 @@ class FeedbackEmail extends Mailable implements ShouldQueue
|
|||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [new RateLimited('emails', releaseAfter: 1)];
|
||||
return [(new RateLimited('emails'))->releaseAfter(1)];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,6 @@ class ImportHelpEmail extends Mailable implements ShouldQueue
|
|||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [new RateLimited('emails', releaseAfter: 1)];
|
||||
return [(new RateLimited('emails'))->releaseAfter(1)];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,6 @@ class OnboardingReminderEmail extends Mailable implements ShouldQueue
|
|||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [new RateLimited('emails', releaseAfter: 1)];
|
||||
return [(new RateLimited('emails'))->releaseAfter(1)];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,6 +59,6 @@ class PromoCodeEmail extends Mailable implements ShouldQueue
|
|||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [new RateLimited('emails', releaseAfter: 1)];
|
||||
return [(new RateLimited('emails'))->releaseAfter(1)];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,6 +58,6 @@ class WelcomeEmail extends Mailable implements ShouldQueue
|
|||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [new RateLimited('emails', releaseAfter: 1)];
|
||||
return [(new RateLimited('emails'))->releaseAfter(1)];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,6 @@ class UserLeadInvitation extends Mailable implements ShouldQueue
|
|||
*/
|
||||
public function middleware(): array
|
||||
{
|
||||
return [new RateLimited('emails', releaseAfter: 1)];
|
||||
return [(new RateLimited('emails'))->releaseAfter(1)];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue