150 lines
5.8 KiB
PHP
150 lines
5.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
usesApiSuite();
|
|
|
|
it('lets customer booking sessions read their own customer attributes', function (): void {
|
|
api_test_covers('GET /customer/attributes', 'customer-access');
|
|
|
|
$session = api_fixtures()->createUserSession(['user']);
|
|
api_fixtures()->addCustomerAttribute((int)$session['user']['id'], 'onlyTankCleaning');
|
|
|
|
$response = api_client()->get(
|
|
'/customer/attributes?customer_number=' . (int)$session['user']['customer_number'],
|
|
$session['headers']
|
|
);
|
|
|
|
$response
|
|
->assertStatus(200)
|
|
->assertEnvelope()
|
|
->assertSuccess();
|
|
|
|
$attributes = array_map(
|
|
static fn(array $attribute): string => (string)($attribute['attribute'] ?? ''),
|
|
is_array($response->data()) ? $response->data() : []
|
|
);
|
|
|
|
expect($attributes)->toContain('onlyTankCleaning');
|
|
expect($response->body)->not->toContain('list_customer_attributes');
|
|
});
|
|
|
|
it('keeps customer attribute reads scoped to the authenticated customer', function (): void {
|
|
api_test_covers('GET /customer/attributes', 'customer-access');
|
|
|
|
$session = api_fixtures()->createUserSession(['user']);
|
|
$otherCustomer = api_fixtures()->createUser(['display_name' => 'Other Attribute Customer']);
|
|
api_fixtures()->addCustomerAttribute((int)$otherCustomer['id'], 'onlyTankCleaning');
|
|
|
|
$response = api_client()->get(
|
|
'/customer/attributes?customer_number=' . (int)$otherCustomer['customer_number'],
|
|
$session['headers']
|
|
);
|
|
|
|
$response
|
|
->assertStatus(403)
|
|
->assertEnvelope()
|
|
->assertSuccess(false)
|
|
->assertMissingPermissions(['list_customer_attributes']);
|
|
});
|
|
|
|
it('still lets attribute managers read another customer attributes', function (): void {
|
|
api_test_covers('GET /customer/attributes', 'permissions');
|
|
|
|
$session = api_fixtures()->createUserSession(['list_customer_attributes']);
|
|
$customer = api_fixtures()->createUser(['display_name' => 'Managed Attribute Customer']);
|
|
api_fixtures()->addCustomerAttribute((int)$customer['id'], 'onlyTankCleaning');
|
|
|
|
$response = api_client()->get(
|
|
'/customer/attributes?customer_number=' . (int)$customer['customer_number'],
|
|
$session['headers']
|
|
);
|
|
|
|
$response
|
|
->assertStatus(200)
|
|
->assertEnvelope()
|
|
->assertSuccess();
|
|
|
|
$attributes = array_map(
|
|
static fn(array $attribute): string => (string)($attribute['attribute'] ?? ''),
|
|
is_array($response->data()) ? $response->data() : []
|
|
);
|
|
|
|
expect($attributes)->toContain('onlyTankCleaning');
|
|
});
|
|
|
|
it('returns exact product restrictions for product-impact attributes and null for workflow attributes', function (): void {
|
|
api_test_covers('GET /customer/attributes', 'product_restrictions');
|
|
|
|
$session = api_fixtures()->createUserSession(['list_customer_attributes']);
|
|
$customer = api_fixtures()->createUser(['display_name' => 'Configured Attribute Customer']);
|
|
api_fixtures()->addCustomerAttribute((int)$customer['id'], 'restrictSpotFree');
|
|
api_fixtures()->addCustomerAttribute((int)$customer['id'], 'exemptFromAdministrationFee');
|
|
$product = api_fixtures()->createProduct(['name' => 'Configured exact rinse']);
|
|
|
|
new \classes\customer_rule_product_restriction_service();
|
|
$db = api_test_runtime()->db();
|
|
$collectionResult = $db->query(
|
|
"SELECT id FROM customer_rule_product_collections
|
|
WHERE attribute = 'restrictSpotFree' ORDER BY sort_order, id LIMIT 1"
|
|
);
|
|
$collectionId = (int)$collectionResult->fetch_assoc()['id'];
|
|
$db->query(
|
|
"INSERT IGNORE INTO customer_rule_product_collection_products (collection_id, product_id)
|
|
VALUES ({$collectionId}, " . (int)$product['id'] . ')'
|
|
);
|
|
api_fixtures()->cleanupDeleteWhere('customer_rule_product_collection_products', [
|
|
'collection_id' => $collectionId,
|
|
'product_id' => (int)$product['id'],
|
|
]);
|
|
|
|
$response = api_client()->get(
|
|
'/customer/attributes?customer_number=' . (int)$customer['customer_number'],
|
|
$session['headers']
|
|
);
|
|
$response->assertStatus(200)->assertEnvelope()->assertSuccess();
|
|
|
|
$byAttribute = [];
|
|
foreach ($response->data() as $attribute) {
|
|
$byAttribute[(string)$attribute['attribute']] = $attribute;
|
|
}
|
|
expect($byAttribute['restrictSpotFree']['product_restriction']['disabled_product_ids'] ?? [])
|
|
->toContain((int)$product['id'])
|
|
->and($byAttribute['restrictSpotFree']['product_restriction']['collections'] ?? [])->not->toBeEmpty()
|
|
->and($byAttribute['exemptFromAdministrationFee']['product_restriction'] ?? 'missing')->toBeNull();
|
|
});
|
|
|
|
it('keeps workflow-only customer attribute activation compatible', function (): void {
|
|
api_test_covers('POST /customer/attributes', 'workflow_compatibility');
|
|
api_test_covers('DELETE /customer/attributes', 'workflow_compatibility');
|
|
|
|
$session = api_fixtures()->createUserSession([
|
|
'list_customer_attributes',
|
|
'add_customer_attribute',
|
|
'delete_customer_attribute',
|
|
]);
|
|
$customer = api_fixtures()->createUser(['display_name' => 'Workflow Attribute Customer']);
|
|
|
|
api_client()->post('/customer/attributes', [
|
|
'user_id' => (int)$customer['id'],
|
|
'attribute' => 'exemptFromAdministrationFee',
|
|
], $session['headers'])
|
|
->assertStatus(200)
|
|
->assertEnvelope()
|
|
->assertSuccess();
|
|
|
|
$listed = api_client()->get(
|
|
'/customer/attributes?customer_number=' . (int)$customer['customer_number'],
|
|
$session['headers']
|
|
);
|
|
expect(array_column($listed->data(), 'attribute'))->toContain('exemptFromAdministrationFee');
|
|
|
|
api_client()->delete(
|
|
'/customer/attributes?user_id=' . (int)$customer['id'] . '&attribute=exemptFromAdministrationFee',
|
|
$session['headers']
|
|
)
|
|
->assertStatus(200)
|
|
->assertEnvelope()
|
|
->assertSuccess();
|
|
});
|