Skip to main content
cancel
Showing results for 
Search instead for 
Did you mean: 

Register now to learn Fabric in free live sessions led by the best Microsoft experts. From Apr 16 to May 9, in English and Spanish.

Reply
D3K
Advocate II
Advocate II

Stocks redistribution Table

Hello everyone!

I have a really compliсated task to make it by myself, believe I've tried 🙂  so asking for help here.

 

We have a database with Stores, Products, Sales History and Current Stocks.

The goal is to redistibute stocks from stores WITH stocks and NO sales to stores WITHOUT stocks and WITH sales in the past.

 

Please see the the attached image.

For example, as you can see in Store 1 we have 5pcs of Product A and no sales. So we need to move it to Stores 2 and 4, where there is no stocks, but these stores needs Product A, cause they can sell it. 

And also we need to do nothing for Store 3, cause it has both of sales and stocks.

 

So I need to make a visual table like on the image below

 

Any help will be highly appreciated. Thanks a lot!

 

2021-06-09_17-36-23.png

 

2 ACCEPTED SOLUTIONS
Anonymous
Not applicable

Here's the solution:

daxer_0-1623266659994.pngdaxer_1-1623266721220.png

You use the Filter Pane of the table above with the [Is True Target Store] measure to obtain the above.

daxer_2-1623266795643.png

daxer_3-1623266867742.png

And here's what needs to be created in PQ behind the scenes:

// SalesAndStockBaseTable
let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCi7JL0pVMDBU0lFyBGIgMlWK1YGLG0HFjUFySOLGUHEjdA0mSBLI4qYIC8yRxc2AAk4QcWRhc6iwKZq4BUK5oRGyhCVWcwwNEMLGSrGxAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Store ID" = _t, ProductID = _t, #"Sales Qty" = _t, #"Stock Qty" = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"Store ID", type text}, {"ProductID", type text}, {"Sales Qty", Int64.Type}, {"Stock Qty", Int64.Type}}),
    #"Added Custom" = Table.AddColumn(#"Changed Type", "Store Type", 
        each 
        let
            StockQty = if [Stock Qty] = null then 0 else [Stock Qty],
            SalesQty = if [Sales Qty] = null then 0 else [Sales Qty],
            Output = 
                if StockQty > 0 and SalesQty = 0 then "Source Store" 
                else 
                if StockQty = 0 and SalesQty > 0 then "Target Store" 
                else 
                    "Neutral Store"
        in
            Output
    )
in
    #"Added Custom"

// Stores
let
    Source = SalesAndStockBaseTable,
    #"Removed Other Columns" = Table.SelectColumns(Source,{"Store ID", "Store Type"}),
    #"Removed Duplicates" = Table.Distinct(#"Removed Other Columns")
in
    #"Removed Duplicates"

// Products
let
    Source = SalesAndStockBaseTable,
    #"Removed Other Columns" = Table.SelectColumns(Source,{"ProductID"}),
    #"Removed Duplicates" = Table.Distinct(#"Removed Other Columns")
in
    #"Removed Duplicates"

// Target Stores
let
    Source = Stores,
    #"Filtered Rows" = Table.SelectRows(Source, each ([Store Type] = "Target Store")),
    #"Removed Columns" = Table.RemoveColumns(#"Filtered Rows",{"Store Type"}),
    #"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Store ID", "Target Store ID"}})
in
    #"Renamed Columns"

// Sales and Stock
let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCi7JL0pVMDBU0lFyBGIgMlWK1YGLG0HFjUFySOLGUHEjdA0mSBLI4qYIC8yRxc2AAk4QcWRhc6iwKZq4BUK5oRGyhCVWcwwNEMLGSrGxAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Store ID" = _t, ProductID = _t, #"Sales Qty" = _t, #"Stock Qty" = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"Store ID", type text}, {"ProductID", type text}, {"Sales Qty", Int64.Type}, {"Stock Qty", Int64.Type}}),
    #"Added Custom" = Table.AddColumn(#"Changed Type", "Store Type", 
        each 
        let
            StockQty = if [Stock Qty] = null then 0 else [Stock Qty],
            SalesQty = if [Sales Qty] = null then 0 else [Sales Qty],
            Output = 
                if StockQty > 0 and SalesQty = 0 then "Source Store" 
                else 
                if StockQty = 0 and SalesQty > 0 then "Target Store" 
                else 
                    "Neutral Store"
        in
            Output
    ),
    #"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"Store Type"})
in
    #"Removed Columns"

View solution in original post

Anonymous
Not applicable

Current Stocks = 
var StoreInScope = ISINSCOPE( Stores[Store ID] ) 
var ProductInScope = ISINSCOPE( Products[ProductID] )
var BothInScope = StoreInScope && ProductInScope
var Result =
    if( BothInScope,
        sum( 'Sales and Stock'[Stock Qty] )
    )
return
    Result
Is True Target Store = 
var SourceStoreInScope = ISINSCOPE( Stores[Store ID] )
var SourceStoreIsReallySource = 
    SELECTEDVALUE( Stores[Store Type] ) = "Source Store"
var TargetStoreInScope = ISINSCOPE( 'Target Stores'[Target Store ID] )
var TargetStoreNotBlank =
    // It could be blank due to the additional row
    // generated by DAX in the Target Stores table
    // after enabling the relationship which has
    // referential integrity violations (but this is
    // how it should be since not all stores are
    // target stores).
    NOT ISBLANK( SELECTEDVALUE( 'Target Stores'[Target Store ID] ) )
var ProductInScope = ISINSCOPE( Products[ProductID] )
var AllThreeInScope = TRUE()
    && SourceStoreInScope
    && SourceStoreIsReallySource
    && TargetStoreInScope
    && TargetStoreNotBlank
    && ProductInScope
var IsCurrentTargetStoreForCurrentProduct =
    if( AllThreeInScope,
        CALCULATE(
            NOT ISEMPTY( 'Sales and Stock' ),
            // Remove filters from Stores
            ALL( Stores ),
            // Enable filtering from the Target Stores
            USERELATIONSHIP(
                'Target Stores'[Target Store ID],
                'Sales and Stock'[Store ID]
            )
        )
    )
return
    // I multiply by 1 to return an int
    // so that the Filter Pane can work
    // with this measure.
    1 * IsCurrentTargetStoreForCurrentProduct

View solution in original post

7 REPLIES 7
Anonymous
Not applicable

Current Stocks = 
var StoreInScope = ISINSCOPE( Stores[Store ID] ) 
var ProductInScope = ISINSCOPE( Products[ProductID] )
var BothInScope = StoreInScope && ProductInScope
var Result =
    if( BothInScope,
        sum( 'Sales and Stock'[Stock Qty] )
    )
return
    Result
Is True Target Store = 
var SourceStoreInScope = ISINSCOPE( Stores[Store ID] )
var SourceStoreIsReallySource = 
    SELECTEDVALUE( Stores[Store Type] ) = "Source Store"
var TargetStoreInScope = ISINSCOPE( 'Target Stores'[Target Store ID] )
var TargetStoreNotBlank =
    // It could be blank due to the additional row
    // generated by DAX in the Target Stores table
    // after enabling the relationship which has
    // referential integrity violations (but this is
    // how it should be since not all stores are
    // target stores).
    NOT ISBLANK( SELECTEDVALUE( 'Target Stores'[Target Store ID] ) )
var ProductInScope = ISINSCOPE( Products[ProductID] )
var AllThreeInScope = TRUE()
    && SourceStoreInScope
    && SourceStoreIsReallySource
    && TargetStoreInScope
    && TargetStoreNotBlank
    && ProductInScope
var IsCurrentTargetStoreForCurrentProduct =
    if( AllThreeInScope,
        CALCULATE(
            NOT ISEMPTY( 'Sales and Stock' ),
            // Remove filters from Stores
            ALL( Stores ),
            // Enable filtering from the Target Stores
            USERELATIONSHIP(
                'Target Stores'[Target Store ID],
                'Sales and Stock'[Store ID]
            )
        )
    )
return
    // I multiply by 1 to return an int
    // so that the Filter Pane can work
    // with this measure.
    1 * IsCurrentTargetStoreForCurrentProduct

Thanks a lot! It works in the best way!

Anonymous
Not applicable

Here's the solution:

daxer_0-1623266659994.pngdaxer_1-1623266721220.png

You use the Filter Pane of the table above with the [Is True Target Store] measure to obtain the above.

daxer_2-1623266795643.png

daxer_3-1623266867742.png

And here's what needs to be created in PQ behind the scenes:

// SalesAndStockBaseTable
let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCi7JL0pVMDBU0lFyBGIgMlWK1YGLG0HFjUFySOLGUHEjdA0mSBLI4qYIC8yRxc2AAk4QcWRhc6iwKZq4BUK5oRGyhCVWcwwNEMLGSrGxAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Store ID" = _t, ProductID = _t, #"Sales Qty" = _t, #"Stock Qty" = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"Store ID", type text}, {"ProductID", type text}, {"Sales Qty", Int64.Type}, {"Stock Qty", Int64.Type}}),
    #"Added Custom" = Table.AddColumn(#"Changed Type", "Store Type", 
        each 
        let
            StockQty = if [Stock Qty] = null then 0 else [Stock Qty],
            SalesQty = if [Sales Qty] = null then 0 else [Sales Qty],
            Output = 
                if StockQty > 0 and SalesQty = 0 then "Source Store" 
                else 
                if StockQty = 0 and SalesQty > 0 then "Target Store" 
                else 
                    "Neutral Store"
        in
            Output
    )
in
    #"Added Custom"

// Stores
let
    Source = SalesAndStockBaseTable,
    #"Removed Other Columns" = Table.SelectColumns(Source,{"Store ID", "Store Type"}),
    #"Removed Duplicates" = Table.Distinct(#"Removed Other Columns")
in
    #"Removed Duplicates"

// Products
let
    Source = SalesAndStockBaseTable,
    #"Removed Other Columns" = Table.SelectColumns(Source,{"ProductID"}),
    #"Removed Duplicates" = Table.Distinct(#"Removed Other Columns")
in
    #"Removed Duplicates"

// Target Stores
let
    Source = Stores,
    #"Filtered Rows" = Table.SelectRows(Source, each ([Store Type] = "Target Store")),
    #"Removed Columns" = Table.RemoveColumns(#"Filtered Rows",{"Store Type"}),
    #"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"Store ID", "Target Store ID"}})
in
    #"Renamed Columns"

// Sales and Stock
let
    Source = Table.FromRows(Json.Document(Binary.Decompress(Binary.FromText("i45WCi7JL0pVMDBU0lFyBGIgMlWK1YGLG0HFjUFySOLGUHEjdA0mSBLI4qYIC8yRxc2AAk4QcWRhc6iwKZq4BUK5oRGyhCVWcwwNEMLGSrGxAA==", BinaryEncoding.Base64), Compression.Deflate)), let _t = ((type nullable text) meta [Serialized.Text = true]) in type table [#"Store ID" = _t, ProductID = _t, #"Sales Qty" = _t, #"Stock Qty" = _t]),
    #"Changed Type" = Table.TransformColumnTypes(Source,{{"Store ID", type text}, {"ProductID", type text}, {"Sales Qty", Int64.Type}, {"Stock Qty", Int64.Type}}),
    #"Added Custom" = Table.AddColumn(#"Changed Type", "Store Type", 
        each 
        let
            StockQty = if [Stock Qty] = null then 0 else [Stock Qty],
            SalesQty = if [Sales Qty] = null then 0 else [Sales Qty],
            Output = 
                if StockQty > 0 and SalesQty = 0 then "Source Store" 
                else 
                if StockQty = 0 and SalesQty > 0 then "Target Store" 
                else 
                    "Neutral Store"
        in
            Output
    ),
    #"Removed Columns" = Table.RemoveColumns(#"Added Custom",{"Store Type"})
in
    #"Removed Columns"

Thanks a lot for this elegant solution!

But I've missed 2 measures, used in this algorithm: "Current Stocks" and "Is True Target Store"

 

Can you add it here? Thank you 

Anonymous
Not applicable

OK, I think I know what you mean now.

Anonymous
Not applicable

You should be more detailed in your description of the algorithm to cover all possible cases.

I'll try

If a store has zero sales of Product A and has stocks of Product A more than 0, we need to take it's stocks and move it to the stores, which needs Product A - has sales of that Product X more than 0 and zero stocks. 

So we need to see the list of such stores (which has sales and no stocks) 

 

For example (please see the table DataBase on the image above):

1. We have a Store 1, where Product A has no sales and stocks in quantity of 5pcs.
2. We have Store 2 and Store 4, where sales of Product A are more than 0 and zero stocks (marked red)

3. We need to get the list of stores (point 2), where we can move Product A from Store 1 (point 1).

 

Store 1 is a source of Product A, Stores 2 and 4 are the target for Product A.

 

It's kind of recomendation, that "You can move Product A to Store 2 or Store 4, because they need this Product A".

User need to see next information:

Store 1 - Product A -> Store 2
Store 1 - Product A -> Store 4

Like on the image above (right table "Move products" - this is what I need in the final).

 

Please let me know, if I can give more information

Thanks

Helpful resources

Announcements
Microsoft Fabric Learn Together

Microsoft Fabric Learn Together

Covering the world! 9:00-10:30 AM Sydney, 4:00-5:30 PM CET (Paris/Berlin), 7:00-8:30 PM Mexico City

PBI_APRIL_CAROUSEL1

Power BI Monthly Update - April 2024

Check out the April 2024 Power BI update to learn about new features.

April Fabric Community Update

Fabric Community Update - April 2024

Find out what's new and trending in the Fabric Community.