When do FPOs pay farmers? Member-level accounting with fpoValue

library(fpoValue)

Farmer producer organisations (FPOs) are expected to raise farmers’ returns through collective marketing, aggregation, grading and bulk procurement. An FPO can, however, generate a surplus that is retained, absorbed by costs or captured by a few large suppliers. fpoValue therefore keeps two accounts: the FPO account (what the organisation earns) and the member account (what each farmer gains relative to marketing alone), and reports how the value created is distributed.

All data below are simulated and illustrative.

A simulated FPO

set.seed(11)
n <- 80
size <- sample(c("marginal", "small", "medium", "large"), n, replace = TRUE,
               prob = c(0.45, 0.30, 0.17, 0.08))
q <- round(c(marginal = 6, small = 14, medium = 30, large = 70)[size] *
             stats::rlnorm(n, 0, 0.3), 1)
dist_market <- round(stats::runif(n, 15, 35))
dist_centre <- round(stats::runif(n, 1, 6))
table(size)
#> size
#>    large marginal   medium    small 
#>        2       48        9       21

1. Transaction costs of each channel

Selling individually in the wholesale market involves long trips in small vehicles, commission, fees and waiting time. Delivering to a nearby FPO collection centre involves short trips but later payment.

mandi <- transaction_costs(q, price = 1500, distance = dist_market,
                           vehicle_capacity = 10, cost_per_km = 12,
                           fixed_per_trip = 80, commission = 0.04,
                           market_fee = 15, time_hours = 6, wage = 45,
                           rejection = 0.02, payment_delay = 3)
centre <- transaction_costs(q, price = 1500, distance = dist_centre,
                            vehicle_capacity = 10, cost_per_km = 12,
                            time_hours = 1.5, wage = 45,
                            payment_delay = 12)
tapply(mandi$per_unit, size, mean)
#>    large marginal   medium    small 
#> 219.9702 266.3598 216.0323 243.2731
tapply(centre$per_unit, size, mean)
#>    large marginal   medium    small 
#> 18.23439 33.54076 22.60657 28.10120

Because transport is trip-based, the smallest sellers pay the most per unit when they market alone, which is the first source of progressive gains.

2. Scale economies from aggregation

agg <- aggregation_savings(q, distance_market = dist_market,
                           distance_centre = dist_centre,
                           small_capacity = 10, small_cost_per_km = 12,
                           small_fixed_trip = 80, bulk_capacity = 90,
                           bulk_cost_per_km = 48, bulk_fixed_trip = 600,
                           input_quantity = q / 6, input_price = 1350,
                           discount_tiers = data.frame(
                             min_quantity = c(20, 100, 300),
                             discount = c(0.02, 0.05, 0.08)),
                           grade_shares = c(0.45, 0.35, 0.20),
                           grade_prices = c(1850, 1550, 1100),
                           ungraded_price = 1500, grading_cost = 25)
agg
#> Scale economies from aggregation
#> 
#>     source     total per_unit_marketed share
#>  transport 34,506.60             34.30 29.7%
#>     inputs 11,316.38             11.25  9.7%
#>    grading 70,413.00             70.00 60.6%
#> 
#> Total potential saving: 116,235.97 (115.55 per unit marketed)

3. Surplus versus member benefit

The FPO buys at 1,540, sells graded produce at 1,660, runs a small input business and pays half of its surplus as patronage dividends.

mb <- member_benefit(q, outside_price = 1500, member_price = 1540,
                     sale_price = 1660, outside_cost = mandi$per_unit,
                     member_cost = centre$per_unit, handling_cost = 55,
                     fixed_cost = 30000, input_quantity = q / 6,
                     input_market_price = 1350, input_member_price = 1310,
                     input_bulk_price = 1260, dividend_share = 0.5,
                     group = size)
mb
#> FPO surplus and member benefit accounting
#> 
#> FPO account
#>   Output margin:          65,383.50
#>   Input margin:           8,382.50
#>   Fixed cost:             30,000.00
#>   Net surplus:            43,766.00
#>   Dividends / retained:   21,883.00 / 21,883.00
#> 
#> Value created:            299,658.84
#> Received by members:      277,775.84 (92.7%)
#> Member benefit per unit:  276.15
#> 
#> Benefit channels: price 40,236.00, transaction cost 208,950.84, inputs 6,706.00, dividends 21,883.00
#> Distribution: Gini 0.376, concentration index 0.374; smallest half of suppliers receive 25.3% of benefits for 23.0% of volume; 0.0% of members worse off
mb$distribution$by_group
#>      group members member_share quantity_share benefit_share benefit_per_member
#> 1 marginal      48       0.6000      0.3034099     0.3201332           1852.610
#> 2    small      21       0.2625      0.3158366     0.3186092           4214.378
#> 3    large       2       0.0250      0.1307287     0.1279849          17775.559
#> 4   medium       9       0.1125      0.2500249     0.2332727           7199.725
#>   benefit_per_unit
#> 1         291.3672
#> 2         278.5708
#> 3         270.3507
#> 4         257.6442

The concentration index ranks members by quantity: values below the Gini coefficient indicate that smaller suppliers gain more per unit than larger ones, and the group table shows benefit shares against quantity shares.

Changing the pricing and dividend policy

Paying a lower procurement price and retaining more surplus raises the FPO’s surplus but lowers the share of value that reaches members.

policy <- expand.grid(member_price = c(1520, 1540, 1560),
                      dividend_share = c(0, 0.5, 1))
policy$member_share <- mapply(function(p, d) {
  member_benefit(q, 1500, p, 1660, outside_cost = mandi$per_unit,
                 member_cost = centre$per_unit, handling_cost = 55,
                 fixed_cost = 30000, dividend_share = d)$value[["member_share"]]
}, policy$member_price, policy$dividend_share)
xtabs(round(member_share, 3) ~ member_price + dividend_share, policy)
#>             dividend_share
#> member_price     0   0.5     1
#>         1520 0.805 0.902 1.000
#>         1540 0.876 0.938 1.000
#>         1560 0.946 0.973 1.000

4. Break-even volume

break_even_volume(fixed_cost = 30000, sale_price = 1660,
                  member_price = c(1520, 1540, 1560), handling_cost = 55,
                  input_margin = sum(q / 6) * 50,
                  avg_member_volume = mean(q), current_volume = sum(q))
#>   fixed_cost sale_price member_price handling_cost unit_margin
#> 1      30000       1660         1520            55          85
#> 2      30000       1660         1540            55          65
#> 3      30000       1660         1560            55          45
#>   break_even_volume members_needed current_volume margin_of_safety
#> 1          254.3235             21         1005.9        0.7471682
#> 2          332.5769             27         1005.9        0.6693738
#> 3          480.3889             39         1005.9        0.5224288
#>   max_member_price
#> 1         1583.509
#> 2         1583.509
#> 3         1583.509

max_member_price is the highest price the FPO can pay at its current volume without making a loss.

5. Collective marketing scenarios

sc <- data.frame(
  scenario = c("village trader", "individual mandi", "FPO pooled",
               "FPO graded", "FPO-processor contract"),
  member_price = c(1380, 1500, 1520, 1540, 1580),
  member_cost = c(mean(centre$per_unit), mean(mandi$per_unit),
                  mean(centre$per_unit), mean(centre$per_unit) + 10,
                  mean(centre$per_unit) + 10),
  sale_price = c(NA, NA, 1620, 1660, 1720),
  handling_cost = c(0, 0, 45, 55, 70),
  fixed_cost = c(0, 0, 20000, 30000, 40000),
  dividend_share = c(0, 0, 0.5, 0.5, 0.5))
res <- collective_marketing_scenarios(q, sc, baseline = "individual mandi",
                                      group = size)
res
#> Collective marketing scenarios (baseline: individual mandi)
#> 
#>                scenario member_net_return net_return_per_unit member_gain
#>          village trader      1,357,461.93            1,349.50  103,585.39
#>        individual mandi      1,253,876.54            1,246.52        0.00
#>              FPO pooled      1,515,950.18            1,507.06  262,073.64
#>              FPO graded      1,526,038.68            1,517.09  272,162.14
#>  FPO-processor contract      1,563,789.43            1,554.62  309,912.89
#>  fpo_surplus  retained value_created member_share_of_value share_better_off
#>         0.00      0.00    103,585.39                100.0%           100.0%
#>         0.00      0.00          0.00                    NA             0.0%
#>    35,324.50 17,662.25    279,735.89                 93.7%           100.0%
#>    35,383.50 17,691.75    289,853.89                 93.9%           100.0%
#>    30,413.00 15,206.50    325,119.39                 95.3%           100.0%
#>  bottom50_gain
#>      23,839.36
#>           0.00
#>      60,314.19
#>      62,635.98
#>      71,324.02
#> 
#> Mean gain per member by group
#>          village trader individual mandi FPO pooled FPO graded
#> marginal         654.77                0    1656.58    1720.35
#> small           1557.91                0    3941.54    4093.27
#> large           6770.79                0   17130.27   17789.70
#> medium          2877.66                0    7280.55    7560.81
#>          FPO-processor contract
#> marginal                1958.97
#> small                   4661.04
#> large                  20257.25
#> medium                  8609.55
plot(res, las = 2, cex.names = 0.7)