import grails.test.*
import com.henyo.BaseUnitTestCase
import static org.junit.Assert.assertThat
import static org.hamcrest.CoreMatchers.equalTo

/**
 * Unit tests for PurchaseOrderService class.
 */
class PurchaseOrderServiceTests extends BaseUnitTestCase {
    def pos = new PurchaseOrderService()

    protected void setUp() {
        super.setUp()
        mockDomain(PurchaseOrder)
        mockDomain(PurchaseOrderNumber)
        mockDomain(Supplier)
        mockDomain(SupplierType)
    }

    protected void tearDown() {
        super.tearDown()
    }

    void testSavePurchaseOrderNumberExpectCommit() {
        mockForTransaction(PurchaseOrderNumber)

        def p = [value: "P100"]
        def r = pos.savePurchaseOrderNumber(p)

        assert ! r.error
        assert PurchaseOrderNumber.count() == 1
    }

    void testSavePurchaseOrderNumberExpectRollback() {
        mockForTransaction(PurchaseOrderNumber, true)

        def p = [value: ""]
        def r = pos.savePurchaseOrderNumber(p)

        assert r.error
        assert PurchaseOrderNumber.count() == 0
    }

    void testSavePurchaseOrderNumberRangeExpectCommit() {
        mockForTransaction(PurchaseOrderNumber)

        def r = pos.savePurchaseOrderNumberRange("P", 1000, 1009)

        assert ! r.error
        assert PurchaseOrderNumber.count() == 10
    }

    void testSavePurchaseOrderNumberRangeExpectRollback() {
        mockForTransaction(PurchaseOrderNumber, true)

        def r = pos.savePurchaseOrderNumberRange("P", -1000, 1009)

        assert r.error
        assert PurchaseOrderNumber.count() == 0
    }

    void testFindsFirstUnusedPurchaseOrderWhenAllUnused() {
        mockForTransaction(PurchaseOrderNumber)
        pos.savePurchaseOrderNumberRange("P", 1000, 1009)

        def next = pos.findNextUnusedPurchaseOrderNumber()

        assertThat next.value, equalTo("P1000")
    }

    void testFindsFirstUnusuedPurchaseOrderWhenSomeUsed() {
        mockForTransaction(PurchaseOrderNumber)
        pos.savePurchaseOrderNumberRange("P", 1000, 1009)
        createPurchaseOrders(4)

        def next = pos.findNextUnusedPurchaseOrderNumber()

        assertThat next.value, equalTo("P1004")
    }

    void testFindsNullIfNoUnusedPurchaseOrderNumbers() {
        mockForTransaction(PurchaseOrderNumber)
        pos.savePurchaseOrderNumberRange("P", 1000, 1009)
        createPurchaseOrders(10)

        def next = pos.findNextUnusedPurchaseOrderNumber()

        assertThat next, equalTo(null)
    }

    void testGetOrCreatePurchaseOrderWithExistingOrder() {
        mockForTransaction(PurchaseOrderNumber)
        pos.savePurchaseOrderNumberRange("P", 1000, 1009)
        createPurchaseOrders(3)
        def params=[purchaseOrderNumber:[id:2]]

        def po = pos.getOrCreatePurchaseOrder(params)

        assertThat po.comment, equalTo("Created by test")
        assertThat po.purchaseOrderNumber.value, equalTo("P1001")
    }

    void testGetOrCreatePurchaseOrderWithNoExistingOrder() {
        mockForTransaction(PurchaseOrderNumber)
        pos.savePurchaseOrderNumberRange("P", 1000, 1009)
        createPurchaseOrders(3)
        createSuppliers(1)
        def params=[purchaseOrderNumber:[id:4],supplier:[id:1]]

        def po = pos.getOrCreatePurchaseOrder(params)

        assertThat po.comment, equalTo("")
        assertThat po.purchaseOrderNumber.value, equalTo("P1003")
    }

    void testFindsDraftPurchaseOrderNumbers() {
        mockForTransaction(PurchaseOrderNumber)
        pos.savePurchaseOrderNumberRange("P", 1000, 1009)
        createPurchaseOrders(3)
        releaseOrder(PurchaseOrder.get(2))

        def drafts = pos.findDraftPurchaseOrderNumbers()

        assertThat drafts.size(), equalTo(2)
        assertThat drafts[0].value, equalTo("P1000")
        assertThat drafts[1].value, equalTo("P1002")
    }



    def createPurchaseOrders(int howMany) {
        for (int i=0; i<howMany; i++) {
            def po = new PurchaseOrder(comment:"Created by test", supplier:new Supplier())
            def pon = PurchaseOrderNumber.list()[i]
            pon.purchaseOrder = po;
            po.purchaseOrderNumber = pon;
            po.save(failOnError:true)
            pon.save(failOnError:true)
        }
    }

    def createSuppliers(int howMany) {
        for (int i=0; i<howMany; i++) {
            def supplier = new Supplier(name:"Supplier ${i}", supplierType:new SupplierType())
            supplier.save(failOnError:true)
        }
    }

    def releaseOrder(PurchaseOrder po) {
        po.ordered = new Date()
        po.save(failOnError:true)
    }
}
